This is an analysis performed on the bulk RNA-Seq dataset
The workflow is as follows:
1. Inspect variance in the dataset (Filtering, Normalization, PCA)
2. Perform differential expression analysis (Using limma)
3. Annotate biological signatures found by DEA (GSEA)
library(edgeR)
library(fgsea)
library(qusage)
library(DESeq2)
library(org.Hs.eg.db)
library(ggplot2)
library(enrichR)
library(VennDiagram)
library(ggpubr)
library(ggrepel)
library(PCAtools)
library(RColorBrewer)
library(ggiraph)
library(UpSetR)
library(rhandsontable)
library(nloptr)
library(ggVennDiagram)
library(BiocManager)
library(stringr)
library(knitr)
Counts list
dat = read.csv('/Users/macbookpro/OneDrive/Documents/UDEM/Master/BulkData/data/merged_counts.apr2022.csv',row.names=1)
knitr::kable(dat[1:6, 1:12], caption ="A Knitr kable")
A Knitr kable
| ENSG00000000003 |
TSPAN6 |
131.00 |
46.00 |
65.00 |
83.00 |
59.00 |
79.00 |
98.00 |
56.00 |
57.0 |
220.00 |
74.00 |
| ENSG00000000005 |
TNMD |
1.00 |
1.00 |
0.00 |
0.00 |
2.00 |
2.00 |
1.00 |
0.00 |
0.0 |
5.00 |
1.00 |
| ENSG00000000419 |
DPM1 |
81.00 |
103.00 |
116.00 |
121.00 |
128.00 |
141.00 |
91.00 |
61.00 |
68.0 |
66.00 |
122.00 |
| ENSG00000000457 |
SCYL3 |
91.24 |
105.74 |
158.38 |
120.97 |
107.41 |
115.13 |
93.44 |
64.38 |
69.5 |
74.44 |
168.65 |
| ENSG00000000460 |
C1orf112 |
95.86 |
56.26 |
77.62 |
72.03 |
68.59 |
67.87 |
44.56 |
59.62 |
50.5 |
91.56 |
88.35 |
| ENSG00000000938 |
FGR |
28.00 |
11.00 |
18.00 |
15.00 |
16.00 |
6.00 |
58.00 |
44.00 |
28.0 |
56.00 |
16.00 |
Meta data
meta = read.table('/Users/macbookpro/OneDrive/Documents/UDEM/Master/BulkData/data/meta_data.apr2022.csv',row.names=1,sep = ",")
names(meta)[names(meta) == "type"] <- "lesion_type"
meta$sex = 'M'
meta[which(meta$sample=="AB203"),]$sex = 'F'
meta.tmp <- meta[c(2,7,10,11,12,13)]
knitr::kable(meta.tmp[1:8,], caption ="A Knitr kable")
A Knitr kable
| S13 |
batch1 |
WML |
WM |
Lesion |
AB187 |
M |
| S14 |
batch1 |
NAGM |
Cortical |
Normal |
AB187 |
M |
| S23 |
batch1 |
CL |
Cortical |
Lesion |
AB203 |
F |
| S26 |
batch1 |
WML |
WM |
Lesion |
AB187 |
M |
| S29 |
batch1 |
CL |
Cortical |
Lesion |
AB187 |
M |
| S33 |
batch1 |
CL |
Cortical |
Lesion |
AB200 |
M |
| S37 |
batch1 |
WML |
WM |
Lesion |
AB200 |
M |
| S38 |
batch1 |
NAGM |
Cortical |
Normal |
AB200 |
M |
Define functions for the analysis: - find_enrichments(): For a given
comparison (DEA) extract enrichments for GO(BP), GO(MF), KEGG and
TFT
- fisher_enrichment(): Perform an enrichment of genesets using a fisher
test approach - plot.gene(): Plot gene expression for a given gene
across conditions.
The gmt files contain the genesets for GSEA
go = read.gmt('/Users/macbookpro/OneDrive/Documents/UDEM/Master/BulkData/GO/c5.go.bp.v7.5.1.symbols.gmt')
mf = read.gmt('/Users/macbookpro/OneDrive/Documents/UDEM/Master/BulkData/GO/c5.go.mf.v7.5.1.symbols.gmt')
kegg = read.gmt('/Users/macbookpro/OneDrive/Documents/UDEM/Master/BulkData/GO/c2.cp.kegg.v7.5.1.symbols.gmt')
tft = read.gmt('/Users/macbookpro/OneDrive/Documents/UDEM/Master/BulkData/GO/c3.tft.v7.5.1.symbols.gmt')
sign_cols=c(DN='deepskyblue',NS='grey80',UP='tomato')
plot.gene <- function(x){
gene_id = rownames(subset(resA,gene_name==x))[1]
meta$gene = y$E[gene_id,rownames(meta)]
ggplot(subset(meta,lesion_type!="Mixed"),aes(lesion_type,gene))+geom_boxplot()+geom_point(aes(col=sample))+theme_bw()+ ggtitle(x)
}
# plot.geneP("SOD2",cols=con_colorsP)
plot.geneP <- function(symbol,x='group',cols){
geneid = subset(convP,SYMBOL==symbol)$ENSEMBL
meta.tmp = metadataP
meta.tmp$expr = EP$E[geneid,rownames(meta.tmp)]
meta.tmp$group <- factor(meta.tmp$group , levels=c('CONTROL','NAWM','LESION'))
pl = ggplot(meta.tmp,aes(group,expr,fill=group))+geom_boxplot(width=.75,size=.75)+theme_bw()+scale_fill_manual(values=cols)+
labs(title = symbol, x = "Group", y = "Expr") + xlab("") + ylab("")
return(pl)
}
fisher_enrichment<-function(cluster_markers,pathway,universe,pathway_name){
enrichment_tables=list()
for(cluster in 1:length(cluster_markers)){
cluster_name=names(cluster_markers)[cluster]
output <- lapply(pathway, function(x) {
freq.table <- table(factor(universe %in% as.character(cluster_markers[[cluster]]),
levels = c(TRUE,FALSE)),
factor(universe %in% x,
levels = c(TRUE,FALSE)))
fit <- fisher.test(freq.table, alternative = "greater")
interSection <- intersect(cluster_markers[[cluster]], x)
interSection <- paste(interSection, collapse = ",")
return(value = c(NOM_pval = fit$p.value, INTERSECT = interSection,"OR"=fit$estimate))})
term_names=character()
for (pathway.term in 1:length(output)){
term_names[pathway.term]=pathway[[pathway.term]][1]
}
results=data.frame(do.call("rbind",output))
results$fdr=p.adjust(as.numeric(as.character(results$NOM_pval)),method = "BH")
results=results[order(results$fdr),]
enrichment_tables[[cluster_name]]=results
}
return(enrichment_tables)
}
find_enrichments<-function(resA,n=5,show='both'){
resA.t = resA$t
names(resA.t)=resA$gene_name
if(show=='up'){
resA.bp = subset(fgsea(go,resA.t),NES>0)
resA.mf = subset(fgsea(mf,resA.t),NES>0)
resA.kegg= subset(fgsea(kegg,resA.t),NES>0)
resA.tft= subset(fgsea(tft,resA.t),NES>0)
}else if(show=='down'){
resA.bp = subset(fgsea(go,resA.t),NES<0)
resA.mf = subset(fgsea(mf,resA.t),NES<0)
resA.kegg= subset(fgsea(kegg,resA.t),NES<0)
resA.tft= subset(fgsea(tft,resA.t),NES<0)
}else{
resA.bp = fgsea(go,resA.t)
resA.mf = fgsea(mf,resA.t)
resA.kegg= fgsea(kegg,resA.t)
resA.tft= subset(fgsea(tft,resA.t))
}
resA.bp$GO = 'BP'
resA.mf$GO = 'MF'
resA.kegg$GO = 'KEGG'
out=list(enr=list(bp=resA.bp,mf=resA.mf,kegg=resA.kegg,tft=resA.tft))
enr = rbind(
head(resA.bp[order(resA.bp$padj),],n),
head(resA.mf[order(resA.mf$padj),],n),
head(resA.kegg[order(resA.kegg$padj),],n)
)
enr=data.frame(enr)
enr$pathway=gsub('_',' ',gsub('GO_|KEGG_','',enr$pathway))
enr$pathway=factor(enr$pathway,levels=as.character(enr[order(enr$GO,enr$NES),'pathway']))
p=ggplot(enr,aes(pathway,NES,fill=GO))+geom_col(width=.6,alpha=.6)+geom_col(width=.6,fill=NA,aes(col=GO))+coord_flip()+theme_bw()+geom_vline(xintercept=c(n,n*2)+.5,linetype='dashed')+geom_hline(yintercept=0)
out$plot=p
return(out)
}
##top pathway
topPath<- function(fish ,specific, p ,n){
l=n*10
result <- matrix(NA, l, l)
colnames(result) <- rownames(result) <- rownames(getElement(fish, specific))[1:l]
for(i in 1:l){
for(j in 1:l){
minlist = 0
if(length(unlist(strsplit(fish[[specific]][["INTERSECT"]][i], split = ",")))>=length(unlist(strsplit(fish[[specific]][["INTERSECT"]][j], split = ",")))) minlist=length(unlist(strsplit(fish[[specific]][["INTERSECT"]][j], split = ",")))
else minlist=length(unlist(strsplit(fish[[specific]][["INTERSECT"]][i], split = ",")))
result[i, j] <- length(intersect(unlist(strsplit(fish[[specific]][["INTERSECT"]][i], split = ",")), unlist(strsplit(fish[[specific]][["INTERSECT"]][j], split = ","))))/(minlist)
result[j, i] <- result[i, j]
}
}
listBPspecific = list(c(rownames(result)[1]))
i=1
while(i < l){
j=i
while(j < l){
if(result[i, j] < p){
i=j
listBPspecific <- c(listBPspecific, rownames(result)[j])
j=l
}else {
j=j+1
}
}
if(length(listBPspecific)>n-1)
i=l
}
return(listBPspecific)
}
Differential expression analysis with limma-voom
Filtering to remove lowly expressed genes + Normalization for
composition bias
use the edgeR/limma workflow to filter out lowly expressed
genes. Voom is used to normalize the raw counts. A linear mixed
model is used to fit the expression values. Defining the model is done
with the model.matrix function of edgeR. In the model are included
factors of interest (group). If a batch/patient effect is detected, it
can be added to the model to account for its effect.
d0 <- DGEList(dat[-1])
d0 <- calcNormFactors(d0)
cutoff <- 2
drop <- which(apply(cpm(d0), 1, max) < cutoff)
d <- d0[-drop,]
mm <- model.matrix(~ 0 + lesion_type+batch+sample, data=meta[colnames(d),])
# Without filtering low expressed genes
y <- voom(d0[,rownames(meta)], mm, plot = T)

# Filtering low expressed genes
y <- voom(d[,rownames(meta)], mm, plot = T)

##gene name reference(ref_G)
conv_B=AnnotationDbi::select(org.Hs.eg.db,keys=rownames(y$E),keytype='ENSEMBL',columns=c('GENENAME','SYMBOL'))
'select()' returned 1:many mapping between keys and columns
ref_G=conv_B[!duplicated(conv_B[,1]),]
rownames(ref_G)=ref_G[,1]
##
PCA
Perform a PCA on the normalized samples and identify main
factors of variation.
Data including batch effect
BD <- pca(y$E, metadata = meta)
biplot(BD, colby = 'batch',hline = 0, vline = 0,legendPosition = 'right', lab="",title = "Data including batch effect + patient effect")

Only Batch effect removed from data (color by patient)
BDCorr <- removeBatchEffect(y$E,batch = meta$batch)
BD1 <- pca(BDCorr, metadata = meta)
biplot(BD1, colby = 'sample',shape = 'sex', hline = 0, vline = 0,legendPosition = 'right', lab="",title="Only Batch effect removed from data")

Only Batch effect removed from data (color by batch)
biplot(BD1B, colby = 'batch',hline = 0, vline = 0,legendPosition = 'right', lab="",title="Only Batch effect removed from data")
Patient+Batch effect removed from data (color by sample)
BDCorrBS <- removeBatchEffect(y$E,batch = meta$batch, batch2 = meta$sample)
BD1BS <- pca(BDCorrBS, metadata = meta)
biplot(BD1BS, colby = 'sample',hline = 0, vline = 0,legendPosition = 'right', lab="",title="Batch+Patient effect removed from data")
Patient+Batch effect removed from data (color by lesion_type and
sex)
biplot(BD1BS, colby = 'lesion_type',shape = 'sex',hline = 0, vline = 0,legendPosition = 'right', lab="",title="Batch+Patient effect removed from data")
Specify Contrast(s) of interest
Use a linear model to fit voomed counts (logCPM). Instanciate the
comparisons of interest by using the contrast approach from
limma. Extract the results, annotate the tables and merge them
into a global result dataframe.
fit <- lmFit(y, mm)
Warning message:
In diff.default(xscale) : reached elapsed time limit
contr <- makeContrasts(
A = lesion_typeWML - lesion_typeNAWM,
B = lesion_typeWML - lesion_typeCL,
C = lesion_typeCL - lesion_typeNAGM,
D = lesion_typeNAWM - lesion_typeNAGM,
E = lesion_typePVML - lesion_typeNAWM,
F = lesion_typePVML - lesion_typeWML,
G = lesion_typePVML - lesion_typeCL,
levels = colnames(coef(fit)))
tmp <- contrasts.fit(fit, contr)
tmp <- eBayes(tmp)
resA <- topTable(tmp, sort.by = "P", n = Inf,coef='A')
resB <- topTable(tmp, sort.by = "P", n = Inf,coef='B')
resC <- topTable(tmp, sort.by = "P", n = Inf,coef='C')
resD <- topTable(tmp, sort.by = "P", n = Inf,coef='D')
resE <- topTable(tmp, sort.by = "P", n = Inf,coef='E')
resF <- topTable(tmp, sort.by = "P", n = Inf,coef='F')
resG <- topTable(tmp, sort.by = "P", n = Inf,coef='G')
Comparisons between conditions (Volcano plot)
Plot results in the form of volcano plots. Thresholds used are
adj.P.Val<0.05 & |logFC|>1. Red genes are upregulated in the
first group as found in the subtitle of each graph.
PVML_vs_NAWM
resE$gene_id = rownames(resE)
resE$comp = 'PVML_vs_NAWM'
resE$gene_name = ref_G[rownames(resE),3]
resE=resE[order(-abs(resE$logFC)),]
resE$show = F
resE[1:15,'show']=T
resE$sign = 'NS'
resE[which(resE$adj.P.Val<0.05&resE$logFC>1),'sign']='UP'
resE[which(resE$adj.P.Val<0.05&resE$logFC<(-1)),'sign']='DN'
ggplot(resE,aes(logFC,-log10(P.Value),col=sign))+geom_point_interactive(aes(x=logFC,y=-log10(P.Value),color=sign,tooltip = gene_name,data_id = gene_name))+theme_bw()+scale_color_manual(values=sign_cols)+ geom_label_repel(data=subset(resE,show==T),aes(label=gene_name),col='black',size=3,force=30,fill = alpha(c("white"),0.5))+ggtitle('PVML_vs_NAWM')

WML_vs_NAWM
resA$gene_id = rownames(resA)
resA$comp = 'WML_vs_NAWM'
resA$gene_name = ref_G[rownames(resA),3]
resA=resA[order(-abs(resA$logFC)),]
resA$show = F
resA[1:15,'show']=T
resA$sign = 'NS'
resA[which(resA$adj.P.Val<0.05&resA$logFC>1),'sign']='UP'
resA[which(resA$adj.P.Val<0.05&resA$logFC<(-1)),'sign']='DN'
ggplot(resA,aes(logFC,-log10(P.Value),col=sign))+geom_point_interactive(aes(x=logFC,y=-log10(P.Value),color=sign,tooltip = gene_name,data_id = gene_name))+theme_bw()+scale_color_manual(values=sign_cols)+ geom_label_repel(data=subset(resA,show==T),aes(label=gene_name),col='black',size=3,force=30,fill = alpha(c("white"),0.5))+ggtitle('WML_vs_NAWM')

WML_vs_CL
resB$gene_id = rownames(resB)
resB$comp = 'WML_vs_CL'
resB$gene_name = ref_G[rownames(resB),3]
resB=resB[order(-abs(resB$logFC)),]
resB$show = F
resB[1:15,'show']=T
resB$sign = 'NS'
resB[which(resB$adj.P.Val<0.05&resB$logFC>1),'sign']='UP'
resB[which(resB$adj.P.Val<0.05&resB$logFC<(-1)),'sign']='DN'
ggplot(resB,aes(logFC,-log10(P.Value),col=sign))+geom_point_interactive(aes(x=logFC,y=-log10(P.Value),color=sign,tooltip = gene_name,data_id = gene_name))+theme_bw()+scale_color_manual(values=sign_cols)+ geom_label_repel(data=subset(resB,show==T),aes(label=gene_name),col='black',size=3,force=30,fill = alpha(c("white"),0.5))+ggtitle('WML_vs_CL')

CL_vs_NAGM
resC$gene_id = rownames(resC)
resC$comp = 'CL_vs_NAGM'
resC$gene_name = ref_G[rownames(resC),3]
resC=resC[order(-abs(resC$logFC)),]
resC$show = F
resC[1:15,'show']=T
resC$sign = 'NS'
resC[which(resC$adj.P.Val<0.05&resC$logFC>1),'sign']='UP'
resC[which(resC$adj.P.Val<0.05&resC$logFC<(-1)),'sign']='DN'
ggplot(resC,aes(logFC,-log10(P.Value),col=sign))+geom_point_interactive(aes(x=logFC,y=-log10(P.Value),color=sign,tooltip = gene_name,data_id = gene_name))+theme_bw()+scale_color_manual(values=sign_cols)+ geom_label_repel(data=subset(resC,show==T),aes(label=gene_name),col='black',size=3,force=30,fill = alpha(c("white"),0.5))+ggtitle('CL_vs_NAGM')

NAWM_vs_NAGM
resD$gene_id = rownames(resD)
resD$comp = 'NAWM_vs_NAGM'
resD$gene_name = ref_G[rownames(resD),3]
resD=resD[order(-abs(resD$logFC)),]
resD$show = F
resD[1:15,'show']=T
resD$sign = 'NS'
resD[which(resD$adj.P.Val<0.05&resD$logFC>1),'sign']='UP'
resD[which(resD$adj.P.Val<0.05&resD$logFC<(-1)),'sign']='DN'
ggplot(resD,aes(logFC,-log10(P.Value),col=sign))+geom_point_interactive(aes(x=logFC,y=-log10(P.Value),color=sign,tooltip = gene_name,data_id = gene_name))+theme_bw()+scale_color_manual(values=sign_cols)+ geom_label_repel(data=subset(resD,show==T),aes(label=gene_name),col='black',size=3,force=30,fill = alpha(c("white"),0.5))+ggtitle('NAWM_vs_NAGM')

PVML_vs_WML
resF$gene_id = rownames(resF)
resF$comp = 'PVML_vs_WML'
resF$gene_name = ref_G[rownames(resF),3]
resF=resF[order(-abs(resF$logFC)),]
resF$show = F
resF[1:15,'show']=T
resF$sign = 'NS'
resF[which(resF$adj.P.Val<0.05&resF$logFC>1),'sign']='UP'
resF[which(resF$adj.P.Val<0.05&resF$logFC<(-1)),'sign']='DN'
ggplot(resF,aes(logFC,-log10(P.Value),col=sign))+geom_point_interactive(aes(x=logFC,y=-log10(P.Value),color=sign,tooltip = gene_name,data_id = gene_name))+theme_bw()+scale_color_manual(values=sign_cols)+ geom_label_repel(data=subset(resF,show==T),aes(label=gene_name),col='black',size=3,force=30,fill = alpha(c("white"),0.5))+ggtitle('PVML_vs_WML')

PVML_vs_CL
resG$gene_id = rownames(resG)
resG$comp = 'PVML_vs_CL'
resG$gene_name = ref_G[rownames(resG),3]
resG=resG[order(-abs(resG$logFC)),]
resG$show = F
resG[1:15,'show']=T
resG$sign = 'NS'
resG[which(resG$adj.P.Val<0.05&resG$logFC>1),'sign']='UP'
resG[which(resG$adj.P.Val<0.05&resG$logFC<(-1)),'sign']='DN'
ggplot(resG,aes(logFC,-log10(P.Value),col=sign))+geom_point_interactive(aes(x=logFC,y=-log10(P.Value),color=sign,tooltip = gene_name,data_id = gene_name))+theme_bw()+scale_color_manual(values=sign_cols)+ geom_label_repel(data=subset(resG,show==T),aes(label=gene_name),col='black',size=3,force=30,fill = alpha(c("white"),0.5))+ggtitle('PVML_vs_CL')

Boxplots of select genes demonstrating significant differential gene
expression.
CIBAR2 <- plot.gene("CIBAR2")
DNAH5 <- plot.gene("DNAH5")
irf1 <- plot.gene("IRF1")
LRRIQ1 <- plot.gene("LRRIQ1")
icam1 <- plot.gene("ICAM1")
ODAD2 <- plot.gene("ODAD2")
vcam1 <- plot.gene("VCAM1")
CD24 <- plot.gene("CD24")
dlec1 <- plot.gene("DLEC1")
cfap54 <- plot.gene("CFAP54")
fhad1 <- plot.gene("FHAD1")
dynlt5 <- plot.gene("DYNLT5")
cfap43 <- plot.gene("CFAP43")
rsph1 <- plot.gene("RSPH1")
dnai3 <- plot.gene("DNAI3")
cxcl14 <- plot.gene("CXCL14")
ggarrange(CIBAR2, DNAH5, LRRIQ1, ODAD2, irf1, CD24, icam1, dlec1, cfap54, vcam1, fhad1, dynlt5, cfap43, rsph1, dnai3, cxcl14, ncol = 4, nrow = 4,align = c("hv"), common.legend = TRUE, legend="bottom")


Compare fold-changes across conditions.
df = data.frame(cbind(resE$logFC,resA[rownames(resE),'logFC'],resB[rownames(resE),'logFC'],resF[rownames(resE),'logFC']))
colnames(df)=c('WML_vs_NAWM','PVML_vs_NAWM','WML_vs_CL','PVML_vs_WML')
p1=ggplot(df,aes(WML_vs_NAWM,PVML_vs_NAWM))+geom_point()+theme_bw()+stat_cor()+geom_smooth(method='lm')+ggtitle('Fold-Changes Correlation')
p2=ggplot(df,aes(WML_vs_NAWM,WML_vs_CL))+geom_point()+theme_bw()+stat_cor()+geom_smooth(method='lm')+ggtitle('Fold-Changes Correlation')
p3=ggplot(df,aes(WML_vs_NAWM,PVML_vs_WML))+geom_point()+theme_bw()+stat_cor()+geom_smooth(method='lm')+ggtitle('Fold-Changes Correlation')
p4=ggplot(df,aes(PVML_vs_NAWM,WML_vs_CL))+geom_point()+theme_bw()+stat_cor()+geom_smooth(method='lm')+ggtitle('Fold-Changes Correlation')
p5=ggplot(df,aes(PVML_vs_NAWM,PVML_vs_WML))+geom_point()+theme_bw()+stat_cor()+geom_smooth(method='lm')+ggtitle('Fold-Changes Correlation')
p6=ggplot(df,aes(WML_vs_CL,PVML_vs_WML))+geom_point()+theme_bw()+stat_cor()+geom_smooth(method='lm')+ggtitle('Fold-Changes Correlation')
p1
`geom_smooth()` using formula 'y ~ x'

p2
`geom_smooth()` using formula 'y ~ x'

p3
`geom_smooth()` using formula 'y ~ x'

p4
`geom_smooth()` using formula 'y ~ x'

p5
`geom_smooth()` using formula 'y ~ x'

p6
`geom_smooth()` using formula 'y ~ x'

Gene ontology term enrichment analysis of comparisons
between conditions
This extracts biological signatures from the transcriptomic changes
found in the differential expression analysis
enr.a=find_enrichments(resA)
enr.b=find_enrichments(resB)
enr.c=find_enrichments(resC)
enr.d=find_enrichments(resD)
enr.e=find_enrichments(resE)
enr.f=find_enrichments(resF)
enr.g=find_enrichments(resG)
Biological Processes
enrA = enr.a$enr$bp
enrA=enrA[order(enrA$padj),]
enrA$comp = unique(resA$comp)
enrB = enr.b$enr$bp
enrB=enrB[order(enrB$padj),]
enrB$comp = unique(resB$comp)
enrC = enr.c$enr$bp
enrC=enrC[order(enrC$padj),]
enrC$comp = unique(resC$comp)
enrD = enr.d$enr$bp
enrD=enrD[order(enrD$padj),]
enrD$comp = unique(resD$comp)
enrE = enr.e$enr$bp
enrE=enrE[order(enrE$padj),]
enrE$comp = unique(resE$comp)
enrF = enr.f$enr$bp
enrF=enrF[order(enrF$padj),]
enrF$comp = unique(resF$comp)
enrG = enr.g$enr$bp
enrG=enrG[order(enrG$padj),]
enrG$comp = unique(resG$comp)
paths = c(head(enrA,10)$pathway,
head(enrB,10)$pathway,
head(enrC,10)$pathway,
head(enrD,10)$pathway,
head(enrE,10)$pathway,
head(enrF,10)$pathway,
head(enrG,10)$pathway )
paths=unique(paths)
rb=rbind(enrA[which(enrA$pathway%in%paths),c('pval','leadingEdge','NES','comp','pathway')],
enrB[which(enrB$pathway%in%paths),c('pval','leadingEdge','NES','comp','pathway')],
enrC[which(enrC$pathway%in%paths),c('pval','leadingEdge','NES','comp','pathway')],
enrD[which(enrD$pathway%in%paths),c('pval','leadingEdge','NES','comp','pathway')],
enrE[which(enrE$pathway%in%paths),c('pval','leadingEdge','NES','comp','pathway')],
enrF[ which(enrF$pathway%in%paths),c('pval','leadingEdge','NES','comp','pathway')],
enrG[which(enrG$pathway%in%paths),c('pval','leadingEdge','NES','comp','pathway')])
rb[which(rb$padj>=0.1),'NES']=NA
rb$pathway <- gsub("GOBP", "",rb$pathway)
rb$pathway <- gsub("_", " ",rb$pathway)
ss = strsplit(as.character(rb$leadingEdge),',')
rb$n_genes = unlist(lapply(ss,length))
rb$pval <- as.numeric(rb$pval)
rb[which(rb$pval>=0.1),'pval']=NA
ggplot(na.omit(rb),aes(pathway,comp,fill=NES))+geom_point(aes(size=pval),shape=21)+scale_x_discrete(label = function(x) stringr::str_trunc(x,50))+theme_bw()+coord_flip()+theme(axis.text.x=element_text( angle=60,hjust=1))+scale_fill_gradientn(colors=rev(brewer.pal(11,'RdYlBu')))+ scale_size(trans = 'reverse')+ theme(axis.text = element_text(face="bold"))

Molecular Function
enrA = enr.a$enr$mf
enrA=enrA[order(enrA$padj),]
enrA$comp = unique(resA$comp)
enrB = enr.b$enr$mf
enrB=enrB[order(enrB$padj),]
enrB$comp = unique(resB$comp)
enrC = enr.c$enr$mf
enrC=enrC[order(enrC$padj),]
enrC$comp = unique(resC$comp)
enrD = enr.d$enr$mf
enrD=enrD[order(enrD$padj),]
enrD$comp = unique(resD$comp)
enrE = enr.e$enr$mf
enrE=enrE[order(enrE$padj),]
enrE$comp = unique(resE$comp)
enrF = enr.f$enr$mf
enrF=enrF[order(enrF$padj),]
enrF$comp = unique(resF$comp)
enrG = enr.g$enr$mf
enrG=enrG[order(enrG$padj),]
enrG$comp = unique(resG$comp)
paths = c(head(enrA,10)$pathway,
head(enrB,10)$pathway,
head(enrC,10)$pathway,
head(enrD,10)$pathway,
head(enrE,10)$pathway,
head(enrF,10)$pathway,
head(enrG,10)$pathway )
paths=unique(paths)
rb=rbind(enrA[which(enrA$pathway%in%paths),c('padj','leadingEdge','NES','comp','pathway')],
enrB[which(enrB$pathway%in%paths),c('padj','leadingEdge','NES','comp','pathway')],
enrC[which(enrC$pathway%in%paths),c('padj','leadingEdge','NES','comp','pathway')],
enrD[which(enrD$pathway%in%paths),c('padj','leadingEdge','NES','comp','pathway')],
enrE[which(enrE$pathway%in%paths),c('padj','leadingEdge','NES','comp','pathway')],
enrF[ which(enrF$pathway%in%paths),c('padj','leadingEdge','NES','comp','pathway')],
enrG[which(enrG$pathway%in%paths),c('padj','leadingEdge','NES','comp','pathway')])
rb[which(rb$padj>=0.1),'NES']=NA
rb$pathway <- gsub("GOMF", "",rb$pathway)
rb$pathway <- gsub("_", " ",rb$pathway)
ss = strsplit(as.character(rb$leadingEdge),',')
rb$n_genes = unlist(lapply(ss,length))
ggplot(na.omit(rb),aes(pathway,comp,fill=NES,size=n_genes))+geom_point(shape=21)+scale_x_discrete(label = function(x) stringr::str_trunc(x,50))+theme_bw()+coord_flip()+theme(axis.text.x=element_text(angle=60,hjust=1))+scale_fill_gradientn(colors=rev(brewer.pal(11,'RdYlBu')))

Transcription factor targets
enrA = enr.a$enr$tft
enrA=enrA[order(enrA$padj),]
enrA$comp = unique(resA$comp)
enrB = enr.b$enr$tft
enrB=enrB[order(enrB$padj),]
enrB$comp = unique(resB$comp)
enrC = enr.c$enr$tft
enrC=enrC[order(enrC$padj),]
enrC$comp = unique(resC$comp)
enrD = enr.d$enr$tft
enrD=enrD[order(enrD$padj),]
enrD$comp = unique(resD$comp)
enrE = enr.e$enr$tft
enrE=enrE[order(enrE$padj),]
enrE$comp = unique(resE$comp)
enrF = enr.f$enr$tft
enrF=enrF[order(enrF$padj),]
enrF$comp = unique(resF$comp)
enrG = enr.g$enr$tft
enrG=enrG[order(enrG$padj),]
enrG$comp = unique(resG$comp)
paths = c(head(enrA,10)$pathway,
head(enrB,10)$pathway,
head(enrC,10)$pathway,
head(enrD,10)$pathway,
head(enrE,10)$pathway,
head(enrF,10)$pathway,
head(enrG,10)$pathway )
paths=unique(paths)
rb=rbind(enrA[which(enrA$pathway%in%paths),c('pval','leadingEdge','NES','comp','pathway')],
enrB[which(enrB$pathway%in%paths),c('pval','leadingEdge','NES','comp','pathway')],
enrC[which(enrC$pathway%in%paths),c('pval','leadingEdge','NES','comp','pathway')],
enrD[which(enrD$pathway%in%paths),c('pval','leadingEdge','NES','comp','pathway')],
enrE[which(enrE$pathway%in%paths),c('pval','leadingEdge','NES','comp','pathway')],
enrF[ which(enrF$pathway%in%paths),c('pval','leadingEdge','NES','comp','pathway')],
enrG[which(enrG$pathway%in%paths),c('pval','leadingEdge','NES','comp','pathway')])
rb[which(rb$padj>=0.1),'NES']=NA
rb$pathway <- gsub("_", " ",rb$pathway)
ss = strsplit(as.character(rb$leadingEdge),',')
rb$n_genes = unlist(lapply(ss,length))
rb$pval <- as.numeric(rb$pval)
rb[which(rb$pval>=0.1),'pval']=NA
ggplot(na.omit(rb),aes(pathway,comp,fill=NES))+geom_point(aes(size=pval),shape=21)+scale_x_discrete(label = function(x) stringr::str_trunc(x,50))+theme_bw()+coord_flip()+theme(axis.text.x=element_text( angle=60,hjust=1))+scale_fill_gradientn(colors=rev(brewer.pal(11,'RdYlBu')))+ scale_size(trans = 'reverse')+ theme(axis.text = element_text(face="bold"))

KEGG pathway database
enrA = enr.a$enr$kegg
enrA=enrA[order(enrA$padj),]
enrA$comp = unique(resA$comp)
enrB = enr.b$enr$kegg
enrB=enrB[order(enrB$padj),]
enrB$comp = unique(resB$comp)
enrC = enr.c$enr$kegg
enrC=enrC[order(enrC$padj),]
enrC$comp = unique(resC$comp)
enrD = enr.d$enr$kegg
enrD=enrD[order(enrD$padj),]
enrD$comp = unique(resD$comp)
enrE = enr.e$enr$kegg
enrE=enrE[order(enrE$padj),]
enrE$comp = unique(resE$comp)
enrF = enr.f$enr$kegg
enrF=enrF[order(enrF$padj),]
enrF$comp = unique(resF$comp)
enrG = enr.g$enr$kegg
enrG=enrG[order(enrG$padj),]
enrG$comp = unique(resG$comp)
paths = c(head(enrA,10)$pathway,
head(enrB,10)$pathway,
head(enrC,10)$pathway,
head(enrD,10)$pathway,
head(enrE,10)$pathway,
head(enrF,10)$pathway,
head(enrG,10)$pathway )
paths=unique(paths)
rb=rbind(enrA[which(enrA$pathway%in%paths),c('pval','leadingEdge','NES','comp','pathway')],
enrB[which(enrB$pathway%in%paths),c('pval','leadingEdge','NES','comp','pathway')],
enrC[which(enrC$pathway%in%paths),c('pval','leadingEdge','NES','comp','pathway')],
enrD[which(enrD$pathway%in%paths),c('pval','leadingEdge','NES','comp','pathway')],
enrE[which(enrE$pathway%in%paths),c('pval','leadingEdge','NES','comp','pathway')],
enrF[ which(enrF$pathway%in%paths),c('pval','leadingEdge','NES','comp','pathway')],
enrG[which(enrG$pathway%in%paths),c('pval','leadingEdge','NES','comp','pathway')])
rb[which(rb$padj>=0.1),'NES']=NA
rb$pathway <- gsub("KEGG", "",rb$pathway)
rb$pathway <- gsub("_", " ",rb$pathway)
ss = strsplit(as.character(rb$leadingEdge),',')
rb$n_genes = unlist(lapply(ss,length))
rb$pval <- as.numeric(rb$pval)
rb[which(rb$pval>=0.1),'pval']=NA
ggplot(na.omit(rb),aes(pathway,comp,fill=NES))+geom_point(aes(size=pval),shape=21)+scale_x_discrete(label = function(x) stringr::str_trunc(x,50))+theme_bw()+coord_flip()+theme(axis.text.x=element_text( angle=60,hjust=1))+scale_fill_gradientn(colors=rev(brewer.pal(11,'RdYlBu')))+ scale_size(trans = 'reverse')+ theme(axis.text = element_text(face="bold"))

Plot the overlap between DEGs with an upset plot/Venn Diagram
Overlap of DEGs in comparaisons
res=rbind(resA,resB,resC,resD,resE,resF,resG)
res= na.omit(res)
degsListvs = list(
WML_vs_NAWM=subset(res,comp=='WML_vs_NAWM' & adj.P.Val<0.1 & abs(logFC)>1)$gene_name,
PVML_vs_WML=subset(res,comp=='PVML_vs_WML' & adj.P.Val<0.1 & abs(logFC)>1)$gene_name,
PVML_vs_NAWM=subset(res,comp=='PVML_vs_NAWM' & adj.P.Val<0.1 & abs(logFC)>1)$gene_name,
WML_vs_CL=subset(res,comp=='WML_vs_CL' & adj.P.Val<0.1 & abs(logFC)>1)$gene_name,
NAWM_vs_NAGM=subset(res,comp=='NAWM_vs_NAGM' & adj.P.Val<0.1 & abs(logFC)>1)$gene_name)
degsListUP = list(
WML_vs_NAWM=subset(res,comp=='WML_vs_NAWM' & adj.P.Val<0.1 & (logFC)>1)$gene_name,
PVML_vs_WML=subset(res,comp=='PVML_vs_WML' & adj.P.Val<0.1 & (logFC)>1)$gene_name,
PVML_vs_NAWM=subset(res,comp=='PVML_vs_NAWM' & adj.P.Val<0.1 & (logFC)>1)$gene_name,
WML_vs_CL=subset(res,comp=='WML_vs_CL' & adj.P.Val<0.1 & (logFC)>1)$gene_name,
NAWM_vs_NAGM=subset(res,comp=='NAWM_vs_NAGM' & adj.P.Val<0.1 & (logFC)>1)$gene_name)
degsListDOWN = list(
WML_vs_NAWM=subset(res,comp=='WML_vs_NAWM' & adj.P.Val<0.1 & (logFC)<1)$gene_name,
PVML_vs_WML=subset(res,comp=='PVML_vs_WML' & adj.P.Val<0.1 & (logFC)<1)$gene_name,
PVML_vs_NAWM=subset(res,comp=='PVML_vs_NAWM' & adj.P.Val<0.1 & (logFC)<1)$gene_name,
WML_vs_CL=subset(res,comp=='WML_vs_CL' & adj.P.Val<0.1 & (logFC)<1)$gene_name,
NAWM_vs_NAGM=subset(res,comp=='NAWM_vs_NAGM' & adj.P.Val<0.1 & (logFC)<1)$gene_name)
UpSet plot
upset(fromList(degsListvs),sets = c('WML_vs_NAWM','PVML_vs_WML','PVML_vs_NAWM',"WML_vs_CL","NAWM_vs_NAGM"),order.by='freq',decreasing = c(F),text.scale = c(1.3, 2, 1.5, 1.5, 2, 2))


#upset(fromList(degsListUP),sets = c('WML_vs_NAWM','PVML_vs_WML','PVML_vs_NAWM',"WML_vs_CL","NAWM_vs_NAGM"),order.by='freq',decreasing = c(F),text.scale = c(1.3, 2, 1.5, 1.5, 2, 2))
#upset(fromList(degsListDOWN),sets = c('WML_vs_NAWM','PVML_vs_WML','PVML_vs_NAWM',"WML_vs_CL","NAWM_vs_NAGM"),order.by='freq',decreasing = c(F),text.scale = c(1.3, 2, 1.5, 1.5, 2, 2))
Venn Diagram
#label = "count"
ggVennDiagram(degsListvs,label = "percent", label_alpha = 0)+ scale_fill_distiller(palette = "Reds", direction = 1)

Gene Ontology enrichment analysis of overlapping
genes in comparisons between conditions(The top 5 specific Genesets from
the upsets plot)
WML_vs_NAWM=na.omit(subset(res,comp=='WML_vs_NAWM' & adj.P.Val<0.1 & abs(logFC)>1)$gene_name)
PVML_vs_WML=na.omit(subset(res,comp=='PVML_vs_WML' & adj.P.Val<0.1 & abs(logFC)>1)$gene_name)
PVML_vs_NAWM=na.omit(subset(res,comp=='PVML_vs_NAWM' & adj.P.Val<0.1 & abs(logFC)>1)$gene_name)
CL_vs_NAWM=na.omit(subset(res,comp=='CL_vs_NAWM' & adj.P.Val<0.1 & abs(logFC)>1)$gene_name)
WML_vs_CL=na.omit(subset(res,comp=='WML_vs_CL' & adj.P.Val<0.1 & abs(logFC)>1)$gene_name)
NAWM_vs_NAGM=na.omit(subset(res,comp=='NAWM_vs_NAGM' & adj.P.Val<0.1 & abs(logFC)>1)$gene_name)
specificWML_vs_CL = as.character(WML_vs_CL[!WML_vs_CL%in%WML_vs_NAWM & !WML_vs_CL%in%PVML_vs_WML & !WML_vs_CL%in%PVML_vs_NAWM & !WML_vs_CL%in%CL_vs_NAWM & !WML_vs_CL%in%NAWM_vs_NAGM])
specificPVML_vs_NAWM = as.character(PVML_vs_NAWM[!PVML_vs_NAWM%in%WML_vs_NAWM & !PVML_vs_NAWM%in%PVML_vs_WML & !PVML_vs_NAWM%in%WML_vs_CL & !PVML_vs_NAWM%in%CL_vs_NAWM & !PVML_vs_NAWM%in%NAWM_vs_NAGM])
commonPVML_vs_NAWM.PVML_vs_WML = as.character(PVML_vs_NAWM[!PVML_vs_NAWM%in%WML_vs_NAWM & PVML_vs_NAWM%in%PVML_vs_WML & !PVML_vs_NAWM%in%WML_vs_CL & !PVML_vs_NAWM%in%CL_vs_NAWM & !PVML_vs_NAWM%in%NAWM_vs_NAGM])
commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL = as.character(PVML_vs_NAWM[!PVML_vs_NAWM%in%WML_vs_NAWM & PVML_vs_NAWM%in%PVML_vs_WML & PVML_vs_NAWM%in%WML_vs_CL & !PVML_vs_NAWM%in%CL_vs_NAWM & !PVML_vs_NAWM%in%NAWM_vs_NAGM])
commonPVML_vs_NAWM.WML_vs_CL = as.character(PVML_vs_NAWM[!PVML_vs_NAWM%in%WML_vs_NAWM & !PVML_vs_NAWM%in%PVML_vs_WML & PVML_vs_NAWM%in%WML_vs_CL & !PVML_vs_NAWM%in%CL_vs_NAWM & !PVML_vs_NAWM%in%NAWM_vs_NAGM])
list = list(commonPVML_vs_NAWM.PVML_vs_WML=commonPVML_vs_NAWM.PVML_vs_WML, specificWML_vs_CL=specificWML_vs_CL,specificPVML_vs_NAWM=specificPVML_vs_NAWM, commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL=commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL, commonPVML_vs_NAWM.WML_vs_CL=commonPVML_vs_NAWM.WML_vs_CL )
fishBP = fisher_enrichment(list,go,unique(ref_G$SYMBOL))
fishMF = fisher_enrichment(list,mf,unique(ref_G$SYMBOL))
fishTFT = fisher_enrichment(list,tft,unique(ref_G$SYMBOL))
fishKEGG = fisher_enrichment(list,kegg,unique(ref_G$SYMBOL))
biological processes
enr.specificWML_vs_CL = fishBP$specificWML_vs_CL
enr.specificWML_vs_CL$pathway = rownames(enr.specificWML_vs_CL)
enr.specificWML_vs_CL$fdr <- as.numeric(enr.specificWML_vs_CL$fdr)
enr.specificWML_vs_CL$OR.odds.ratio <- as.numeric(enr.specificWML_vs_CL$OR.odds.ratio)
enr.specificWML_vs_CL$NOM_pval <- as.numeric(enr.specificWML_vs_CL$NOM_pval)
topspecificWML_vs_CL <- topPath(fishBP ,"specificWML_vs_CL", 0.5, 20)
enr.specificWML_vs_CL <- enr.specificWML_vs_CL[match(topspecificWML_vs_CL, rownames(enr.specificWML_vs_CL)),]
rownames(enr.specificWML_vs_CL) <- gsub("GOBP_", "",rownames(enr.specificWML_vs_CL))
enr.specificWML_vs_CL=enr.specificWML_vs_CL[order(enr.specificWML_vs_CL$NOM_pval),]
enr.specificWML_vs_CL$comp = "specificWML_vs_CL"
enr.specificPVML_vs_NAWM = fishBP$specificPVML_vs_NAWM
enr.specificPVML_vs_NAWM$pathway = rownames(enr.specificPVML_vs_NAWM)
enr.specificPVML_vs_NAWM$fdr <- as.numeric(enr.specificPVML_vs_NAWM$fdr)
enr.specificPVML_vs_NAWM$OR.odds.ratio <- as.numeric(enr.specificPVML_vs_NAWM$OR.odds.ratio)
enr.specificPVML_vs_NAWM$NOM_pval <- as.numeric(enr.specificPVML_vs_NAWM$NOM_pval)
topspecificPVML_vs_NAWM <- topPath(fishBP ,"specificPVML_vs_NAWM", 0.5, 20)
enr.specificPVML_vs_NAWM <- enr.specificPVML_vs_NAWM[match(topspecificPVML_vs_NAWM, rownames(enr.specificPVML_vs_NAWM)),]
rownames(enr.specificPVML_vs_NAWM) <- gsub("GOBP_", "",rownames(enr.specificPVML_vs_NAWM))
enr.specificPVML_vs_NAWM=enr.specificPVML_vs_NAWM[order(enr.specificPVML_vs_NAWM$NOM_pval),]
enr.specificPVML_vs_NAWM$comp = "specificPVML_vs_NAWM"
enr.commonPVML_vs_NAWM.PVML_vs_WML = fishBP$commonPVML_vs_NAWM.PVML_vs_WML
enr.commonPVML_vs_NAWM.PVML_vs_WML$pathway = rownames(enr.commonPVML_vs_NAWM.PVML_vs_WML)
enr.commonPVML_vs_NAWM.PVML_vs_WML$fdr <- as.numeric(enr.commonPVML_vs_NAWM.PVML_vs_WML$fdr)
enr.commonPVML_vs_NAWM.PVML_vs_WML$OR.odds.ratio <- as.numeric(enr.commonPVML_vs_NAWM.PVML_vs_WML$OR.odds.ratio)
enr.commonPVML_vs_NAWM.PVML_vs_WML$NOM_pval <- as.numeric(enr.commonPVML_vs_NAWM.PVML_vs_WML$NOM_pval)
topcommonPVML_vs_NAWM.PVML_vs_WML <- topPath(fishBP ,"commonPVML_vs_NAWM.PVML_vs_WML", 0.5, 20)
enr.commonPVML_vs_NAWM.PVML_vs_WML <- enr.commonPVML_vs_NAWM.PVML_vs_WML[match(topcommonPVML_vs_NAWM.PVML_vs_WML, rownames(enr.commonPVML_vs_NAWM.PVML_vs_WML)),]
rownames(enr.commonPVML_vs_NAWM.PVML_vs_WML) <- gsub("GOBP_", "",rownames(enr.commonPVML_vs_NAWM.PVML_vs_WML))
enr.commonPVML_vs_NAWM.PVML_vs_WML=enr.commonPVML_vs_NAWM.PVML_vs_WML[order(enr.commonPVML_vs_NAWM.PVML_vs_WML$NOM_pval),]
enr.commonPVML_vs_NAWM.PVML_vs_WML$comp = "commonPVML_vs_NAWM & PVML_vs_WML"
enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL = fishBP$commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL
enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL$pathway = rownames(enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL)
enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL$fdr <- as.numeric(enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL$fdr)
enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL$OR.odds.ratio <- as.numeric(enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL$OR.odds.ratio)
enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL$NOM_pval <- as.numeric(enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL$NOM_pval)
topcommonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL <- topPath(fishBP ,"commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL", 0.5,20)
enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL <- enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL[match(topcommonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL, rownames(enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL)),]
rownames(enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL) <- gsub("GOBP_", "",rownames(enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL))
enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL=enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL[order(enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL$NOM_pval),]
enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL$comp = "commonPVML_vs_NAWM & PVML_vs_WML & WML_vs_CL"
enr.commonPVML_vs_NAWM.WML_vs_CL = fishBP$commonPVML_vs_NAWM.WML_vs_CL
enr.commonPVML_vs_NAWM.WML_vs_CL$pathway = rownames(enr.commonPVML_vs_NAWM.WML_vs_CL)
enr.commonPVML_vs_NAWM.WML_vs_CL$fdr <- as.numeric(enr.commonPVML_vs_NAWM.WML_vs_CL$fdr)
enr.commonPVML_vs_NAWM.WML_vs_CL$OR.odds.ratio <- as.numeric(enr.commonPVML_vs_NAWM.WML_vs_CL$OR.odds.ratio)
enr.commonPVML_vs_NAWM.WML_vs_CL$NOM_pval <- as.numeric(enr.commonPVML_vs_NAWM.WML_vs_CL$NOM_pval)
topcommonPVML_vs_NAWM.WML_vs_CL <- topPath(fishBP ,"commonPVML_vs_NAWM.WML_vs_CL", 0.5,20)
enr.commonPVML_vs_NAWM.WML_vs_CL <- enr.commonPVML_vs_NAWM.WML_vs_CL[match(topcommonPVML_vs_NAWM.WML_vs_CL, rownames(enr.commonPVML_vs_NAWM.WML_vs_CL)),]
rownames(enr.commonPVML_vs_NAWM.WML_vs_CL) <- gsub("GOBP_", "",rownames(enr.commonPVML_vs_NAWM.WML_vs_CL))
enr.commonPVML_vs_NAWM.WML_vs_CL=enr.commonPVML_vs_NAWM.WML_vs_CL[order(enr.commonPVML_vs_NAWM.WML_vs_CL$NOM_pval),]
enr.commonPVML_vs_NAWM.WML_vs_CL$comp = "commonPVML_vs_NAWM & PVML_vs_WML"
Specific WML_vs_CL
ggplot(enr.specificWML_vs_CL, aes(x=reorder(rownames(enr.specificWML_vs_CL),-rank(NOM_pval)), y=-log10(NOM_pval),fill=-log10(NOM_pval))) + geom_col(width=.65)+ scale_fill_gradient(low="#F6BDC0",high="#DC1C13") +theme(axis.text=element_text(size=8)) + scale_x_discrete(label = function(x) stringr::str_wrap(gsub("_", " ",x), width = 30)) + labs(title = "WML_vs_CL") + xlab("") + coord_flip() + theme_bw()+ theme(axis.text = element_text(face="bold"))

Specific PVML_vs_NAWM
ggplot(enr.specificPVML_vs_NAWM, aes(x=reorder(rownames(enr.specificPVML_vs_NAWM),-rank(NOM_pval)), y=-log10(NOM_pval),fill=-log10(NOM_pval))) + geom_col(width=.65)+ scale_fill_gradient(low="#F6BDC0",high="#DC1C13") +theme(axis.text=element_text(size=8)) + scale_x_discrete(label = function(x) stringr::str_wrap(gsub("_", " ",x), width = 30)) + labs(title = "PVML_vs_NAWM") + xlab("") + coord_flip() + theme_bw()+ theme(axis.text = element_text(face="bold"))

Common PVML_vs_NAWM & PVML_vs_WML
ggplot(enr.commonPVML_vs_NAWM.PVML_vs_WML, aes(x=reorder(rownames(enr.commonPVML_vs_NAWM.PVML_vs_WML),-rank(NOM_pval)), y=-log10(NOM_pval),fill=-log10(NOM_pval))) + geom_col(width=.65)+ scale_fill_gradient(low="#F6BDC0",high="#DC1C13") +theme(axis.text=element_text(size=8)) + scale_x_discrete(label = function(x) stringr::str_wrap(gsub("_", " ",x), width = 30)) + labs(title = "common PVML_vs_NAWM & PVML_vs_WML") + xlab("") + coord_flip() + theme_bw()+ theme(axis.text = element_text(face="bold"))

Common PVML_vs_NAWM & PVML_vs_WML & WML_vs_CL
ggplot(enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL, aes(x=reorder(rownames(enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL),-rank(NOM_pval)), y=-log10(NOM_pval),fill=-log10(NOM_pval))) + geom_col(width=.65)+ scale_fill_gradient(low="#F6BDC0",high="#DC1C13") +theme(axis.text=element_text(size=8)) + scale_x_discrete(label = function(x) stringr::str_wrap(gsub("_", " ",x), width = 30)) + labs(title = "Common PVML_vs_NAWM & PVML_vs_WML & WML_vs_CL") + xlab("") + coord_flip() + theme_bw()+ theme(axis.text = element_text(face="bold"))

Common PVML_vs_NAWM & WML_vs_CL
ggplot(enr.commonPVML_vs_NAWM.WML_vs_CL, aes(x=reorder(rownames(enr.commonPVML_vs_NAWM.WML_vs_CL),-rank(NOM_pval)), y=-log10(NOM_pval),fill=-log10(NOM_pval))) + geom_col(width=.65)+ scale_fill_gradient(low="#F6BDC0",high="#DC1C13") +theme(axis.text=element_text(size=8)) + scale_x_discrete(label = function(x) stringr::str_wrap(gsub("_", " ",x), width = 30)) + labs(title = "Common PVML_vs_NAWM & WML_vs_CL") + xlab("") + coord_flip() + theme_bw()+ theme(axis.text = element_text(face="bold"))

Molecular Function
enr.specificWML_vs_CL = fishMF$specificWML_vs_CL
enr.specificWML_vs_CL$pathway = rownames(enr.specificWML_vs_CL)
enr.specificWML_vs_CL$fdr <- as.numeric(enr.specificWML_vs_CL$fdr)
enr.specificWML_vs_CL$OR.odds.ratio <- as.numeric(enr.specificWML_vs_CL$OR.odds.ratio)
enr.specificWML_vs_CL$NOM_pval <- as.numeric(enr.specificWML_vs_CL$NOM_pval)
topspecificWML_vs_CL <- topPath(fishMF ,"specificWML_vs_CL", 0.5, 20)
enr.specificWML_vs_CL <- enr.specificWML_vs_CL[match(topspecificWML_vs_CL, rownames(enr.specificWML_vs_CL)),]
rownames(enr.specificWML_vs_CL) <- gsub("GOMF_", "",rownames(enr.specificWML_vs_CL))
enr.specificWML_vs_CL=enr.specificWML_vs_CL[order(enr.specificWML_vs_CL$NOM_pval),]
enr.specificWML_vs_CL$comp = "specificWML_vs_CL"
enr.specificPVML_vs_NAWM = fishMF$specificPVML_vs_NAWM
enr.specificPVML_vs_NAWM$pathway = rownames(enr.specificPVML_vs_NAWM)
enr.specificPVML_vs_NAWM$fdr <- as.numeric(enr.specificPVML_vs_NAWM$fdr)
enr.specificPVML_vs_NAWM$OR.odds.ratio <- as.numeric(enr.specificPVML_vs_NAWM$OR.odds.ratio)
enr.specificPVML_vs_NAWM$NOM_pval <- as.numeric(enr.specificPVML_vs_NAWM$NOM_pval)
topspecificPVML_vs_NAWM <- topPath(fishMF ,"specificPVML_vs_NAWM", 0.5, 20)
enr.specificPVML_vs_NAWM <- enr.specificPVML_vs_NAWM[match(topspecificPVML_vs_NAWM, rownames(enr.specificPVML_vs_NAWM)),]
rownames(enr.specificPVML_vs_NAWM) <- gsub("GOMF_", "",rownames(enr.specificPVML_vs_NAWM))
enr.specificPVML_vs_NAWM=enr.specificPVML_vs_NAWM[order(enr.specificPVML_vs_NAWM$NOM_pval),]
enr.specificPVML_vs_NAWM$comp = "specificPVML_vs_NAWM"
enr.commonPVML_vs_NAWM.PVML_vs_WML = fishMF$commonPVML_vs_NAWM.PVML_vs_WML
enr.commonPVML_vs_NAWM.PVML_vs_WML$pathway = rownames(enr.commonPVML_vs_NAWM.PVML_vs_WML)
enr.commonPVML_vs_NAWM.PVML_vs_WML$fdr <- as.numeric(enr.commonPVML_vs_NAWM.PVML_vs_WML$fdr)
enr.commonPVML_vs_NAWM.PVML_vs_WML$OR.odds.ratio <- as.numeric(enr.commonPVML_vs_NAWM.PVML_vs_WML$OR.odds.ratio)
enr.commonPVML_vs_NAWM.PVML_vs_WML$NOM_pval <- as.numeric(enr.commonPVML_vs_NAWM.PVML_vs_WML$NOM_pval)
topcommonPVML_vs_NAWM.PVML_vs_WML <- topPath(fishMF ,"commonPVML_vs_NAWM.PVML_vs_WML", 0.5, 20)
enr.commonPVML_vs_NAWM.PVML_vs_WML <- enr.commonPVML_vs_NAWM.PVML_vs_WML[match(topcommonPVML_vs_NAWM.PVML_vs_WML, rownames(enr.commonPVML_vs_NAWM.PVML_vs_WML)),]
rownames(enr.commonPVML_vs_NAWM.PVML_vs_WML) <- gsub("GOMF_", "",rownames(enr.commonPVML_vs_NAWM.PVML_vs_WML))
enr.commonPVML_vs_NAWM.PVML_vs_WML=enr.commonPVML_vs_NAWM.PVML_vs_WML[order(enr.commonPVML_vs_NAWM.PVML_vs_WML$NOM_pval),]
enr.commonPVML_vs_NAWM.PVML_vs_WML$comp = "commonPVML_vs_NAWM & PVML_vs_WML"
enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL = fishMF$commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL
enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL$pathway = rownames(enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL)
enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL$fdr <- as.numeric(enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL$fdr)
enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL$OR.odds.ratio <- as.numeric(enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL$OR.odds.ratio)
enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL$NOM_pval <- as.numeric(enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL$NOM_pval)
topcommonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL <- topPath(fishMF ,"commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL", 0.5,20)
enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL <- enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL[match(topcommonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL, rownames(enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL)),]
rownames(enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL) <- gsub("GOMF_", "",rownames(enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL))
enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL=enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL[order(enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL$NOM_pval),]
enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL$comp = "commonPVML_vs_NAWM & PVML_vs_WML & WML_vs_CL"
enr.commonPVML_vs_NAWM.WML_vs_CL = fishMF$commonPVML_vs_NAWM.WML_vs_CL
enr.commonPVML_vs_NAWM.WML_vs_CL$pathway = rownames(enr.commonPVML_vs_NAWM.WML_vs_CL)
enr.commonPVML_vs_NAWM.WML_vs_CL$fdr <- as.numeric(enr.commonPVML_vs_NAWM.WML_vs_CL$fdr)
enr.commonPVML_vs_NAWM.WML_vs_CL$OR.odds.ratio <- as.numeric(enr.commonPVML_vs_NAWM.WML_vs_CL$OR.odds.ratio)
enr.commonPVML_vs_NAWM.WML_vs_CL$NOM_pval <- as.numeric(enr.commonPVML_vs_NAWM.WML_vs_CL$NOM_pval)
topcommonPVML_vs_NAWM.WML_vs_CL <- topPath(fishMF ,"commonPVML_vs_NAWM.WML_vs_CL", 0.5,20)
enr.commonPVML_vs_NAWM.WML_vs_CL <- enr.commonPVML_vs_NAWM.WML_vs_CL[match(topcommonPVML_vs_NAWM.WML_vs_CL, rownames(enr.commonPVML_vs_NAWM.WML_vs_CL)),]
rownames(enr.commonPVML_vs_NAWM.WML_vs_CL) <- gsub("GOMF_", "",rownames(enr.commonPVML_vs_NAWM.WML_vs_CL))
enr.commonPVML_vs_NAWM.WML_vs_CL=enr.commonPVML_vs_NAWM.WML_vs_CL[order(enr.commonPVML_vs_NAWM.WML_vs_CL$NOM_pval),]
enr.commonPVML_vs_NAWM.WML_vs_CL$comp = "commonPVML_vs_NAWM & PVML_vs_WML"
Specific WML_vs_CL
ggplot(enr.specificWML_vs_CL, aes(x=reorder(rownames(enr.specificWML_vs_CL),-rank(NOM_pval)), y=-log10(NOM_pval),fill=-log10(NOM_pval))) + geom_col(width=.65)+ scale_fill_gradient(low="#F6BDC0",high="#DC1C13") +theme(axis.text=element_text(size=8)) + scale_x_discrete(label = function(x) stringr::str_wrap(gsub("_", " ",x), width = 30)) + labs(title = "WML_vs_CL") + xlab("") + coord_flip() + theme_bw()+ theme(axis.text = element_text(face="bold"))
Specific PVML_vs_NAWM
ggplot(enr.specificPVML_vs_NAWM, aes(x=reorder(rownames(enr.specificPVML_vs_NAWM),-rank(NOM_pval)), y=-log10(NOM_pval),fill=-log10(NOM_pval))) + geom_col(width=.65)+ scale_fill_gradient(low="#F6BDC0",high="#DC1C13") +theme(axis.text=element_text(size=8)) + scale_x_discrete(label = function(x) stringr::str_wrap(gsub("_", " ",x), width = 30)) + labs(title = "PVML_vs_NAWM") + xlab("") + coord_flip() + theme_bw()+ theme(axis.text = element_text(face="bold"))
Common PVML_vs_NAWM & PVML_vs_WML
ggplot(enr.commonPVML_vs_NAWM.PVML_vs_WML, aes(x=reorder(rownames(enr.commonPVML_vs_NAWM.PVML_vs_WML),-rank(NOM_pval)), y=-log10(NOM_pval),fill=-log10(NOM_pval))) + geom_col(width=.65)+ scale_fill_gradient(low="#F6BDC0",high="#DC1C13") +theme(axis.text=element_text(size=8)) + scale_x_discrete(label = function(x) stringr::str_wrap(gsub("_", " ",x), width = 30)) + labs(title = "common PVML_vs_NAWM & PVML_vs_WML") + xlab("") + coord_flip() + theme_bw()+ theme(axis.text = element_text(face="bold"))
Common PVML_vs_NAWM & PVML_vs_WML & WML_vs_CL
ggplot(enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL, aes(x=reorder(rownames(enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL),-rank(NOM_pval)), y=-log10(NOM_pval),fill=-log10(NOM_pval))) + geom_col(width=.65)+ scale_fill_gradient(low="#F6BDC0",high="#DC1C13") +theme(axis.text=element_text(size=8)) + scale_x_discrete(label = function(x) stringr::str_wrap(gsub("_", " ",x), width = 30)) + labs(title = "Common PVML_vs_NAWM & PVML_vs_WML & WML_vs_CL") + xlab("") + coord_flip() + theme_bw()+ theme(axis.text = element_text(face="bold"))
Common PVML_vs_NAWM & WML_vs_CL
ggplot(enr.commonPVML_vs_NAWM.WML_vs_CL, aes(x=reorder(rownames(enr.commonPVML_vs_NAWM.WML_vs_CL),-rank(NOM_pval)), y=-log10(NOM_pval),fill=-log10(NOM_pval))) + geom_col(width=.65)+ scale_fill_gradient(low="#F6BDC0",high="#DC1C13") +theme(axis.text=element_text(size=8)) + scale_x_discrete(label = function(x) stringr::str_wrap(gsub("_", " ",x), width = 30)) + labs(title = "Common PVML_vs_NAWM & WML_vs_CL") + xlab("") + coord_flip() + theme_bw()+ theme(axis.text = element_text(face="bold"))
Transcription factor targets
enr.specificWML_vs_CL = fishTFT$specificWML_vs_CL
enr.specificWML_vs_CL$pathway = rownames(enr.specificWML_vs_CL)
enr.specificWML_vs_CL$fdr <- as.numeric(enr.specificWML_vs_CL$fdr)
enr.specificWML_vs_CL$OR.odds.ratio <- as.numeric(enr.specificWML_vs_CL$OR.odds.ratio)
enr.specificWML_vs_CL$NOM_pval <- as.numeric(enr.specificWML_vs_CL$NOM_pval)
topspecificWML_vs_CL <- topPath(fishTFT ,"specificWML_vs_CL", 0.5, 20)
enr.specificWML_vs_CL <- enr.specificWML_vs_CL[match(topspecificWML_vs_CL, rownames(enr.specificWML_vs_CL)),]
enr.specificWML_vs_CL=enr.specificWML_vs_CL[order(enr.specificWML_vs_CL$NOM_pval),]
enr.specificWML_vs_CL$comp = "specificWML_vs_CL"
enr.specificPVML_vs_NAWM = fishTFT$specificPVML_vs_NAWM
enr.specificPVML_vs_NAWM$pathway = rownames(enr.specificPVML_vs_NAWM)
enr.specificPVML_vs_NAWM$fdr <- as.numeric(enr.specificPVML_vs_NAWM$fdr)
enr.specificPVML_vs_NAWM$OR.odds.ratio <- as.numeric(enr.specificPVML_vs_NAWM$OR.odds.ratio)
enr.specificPVML_vs_NAWM$NOM_pval <- as.numeric(enr.specificPVML_vs_NAWM$NOM_pval)
topspecificPVML_vs_NAWM <- topPath(fishTFT ,"specificPVML_vs_NAWM", 0.5, 20)
enr.specificPVML_vs_NAWM <- enr.specificPVML_vs_NAWM[match(topspecificPVML_vs_NAWM, rownames(enr.specificPVML_vs_NAWM)),]
enr.specificPVML_vs_NAWM=enr.specificPVML_vs_NAWM[order(enr.specificPVML_vs_NAWM$NOM_pval),]
enr.specificPVML_vs_NAWM$comp = "specificPVML_vs_NAWM"
enr.commonPVML_vs_NAWM.PVML_vs_WML = fishTFT$commonPVML_vs_NAWM.PVML_vs_WML
enr.commonPVML_vs_NAWM.PVML_vs_WML$pathway = rownames(enr.commonPVML_vs_NAWM.PVML_vs_WML)
enr.commonPVML_vs_NAWM.PVML_vs_WML$fdr <- as.numeric(enr.commonPVML_vs_NAWM.PVML_vs_WML$fdr)
enr.commonPVML_vs_NAWM.PVML_vs_WML$OR.odds.ratio <- as.numeric(enr.commonPVML_vs_NAWM.PVML_vs_WML$OR.odds.ratio)
enr.commonPVML_vs_NAWM.PVML_vs_WML$NOM_pval <- as.numeric(enr.commonPVML_vs_NAWM.PVML_vs_WML$NOM_pval)
topcommonPVML_vs_NAWM.PVML_vs_WML <- topPath(fishTFT ,"commonPVML_vs_NAWM.PVML_vs_WML", 0.5, 20)
enr.commonPVML_vs_NAWM.PVML_vs_WML <- enr.commonPVML_vs_NAWM.PVML_vs_WML[match(topcommonPVML_vs_NAWM.PVML_vs_WML, rownames(enr.commonPVML_vs_NAWM.PVML_vs_WML)),]
enr.commonPVML_vs_NAWM.PVML_vs_WML=enr.commonPVML_vs_NAWM.PVML_vs_WML[order(enr.commonPVML_vs_NAWM.PVML_vs_WML$NOM_pval),]
enr.commonPVML_vs_NAWM.PVML_vs_WML$comp = "commonPVML_vs_NAWM & PVML_vs_WML"
enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL = fishTFT$commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL
enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL$pathway = rownames(enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL)
enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL$fdr <- as.numeric(enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL$fdr)
enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL$OR.odds.ratio <- as.numeric(enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL$OR.odds.ratio)
enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL$NOM_pval <- as.numeric(enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL$NOM_pval)
topcommonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL <- topPath(fishTFT ,"commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL", 0.5,20)
enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL <- enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL[match(topcommonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL, rownames(enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL)),]
enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL=enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL[order(enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL$NOM_pval),]
enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL$comp = "commonPVML_vs_NAWM & PVML_vs_WML & WML_vs_CL"
enr.commonPVML_vs_NAWM.WML_vs_CL = fishTFT$commonPVML_vs_NAWM.WML_vs_CL
enr.commonPVML_vs_NAWM.WML_vs_CL$pathway = rownames(enr.commonPVML_vs_NAWM.WML_vs_CL)
enr.commonPVML_vs_NAWM.WML_vs_CL$fdr <- as.numeric(enr.commonPVML_vs_NAWM.WML_vs_CL$fdr)
enr.commonPVML_vs_NAWM.WML_vs_CL$OR.odds.ratio <- as.numeric(enr.commonPVML_vs_NAWM.WML_vs_CL$OR.odds.ratio)
enr.commonPVML_vs_NAWM.WML_vs_CL$NOM_pval <- as.numeric(enr.commonPVML_vs_NAWM.WML_vs_CL$NOM_pval)
topcommonPVML_vs_NAWM.WML_vs_CL <- topPath(fishTFT ,"commonPVML_vs_NAWM.WML_vs_CL", 0.5,20)
enr.commonPVML_vs_NAWM.WML_vs_CL <- enr.commonPVML_vs_NAWM.WML_vs_CL[match(topcommonPVML_vs_NAWM.WML_vs_CL, rownames(enr.commonPVML_vs_NAWM.WML_vs_CL)),]
enr.commonPVML_vs_NAWM.WML_vs_CL=enr.commonPVML_vs_NAWM.WML_vs_CL[order(enr.commonPVML_vs_NAWM.WML_vs_CL$NOM_pval),]
enr.commonPVML_vs_NAWM.WML_vs_CL$comp = "commonPVML_vs_NAWM & PVML_vs_WML"
Specific WML_vs_CL
ggplot(enr.specificWML_vs_CL, aes(x=reorder(rownames(enr.specificWML_vs_CL),-rank(NOM_pval)), y=-log10(NOM_pval),fill=-log10(NOM_pval))) + geom_col(width=.65)+ scale_fill_gradient(low="#F6BDC0",high="#DC1C13") +theme(axis.text=element_text(size=8)) + scale_x_discrete(label = function(x) stringr::str_wrap(gsub("_", " ",x), width = 30)) + labs(title = "WML_vs_CL") + xlab("") + coord_flip() + theme_bw()
Specific PVML_vs_NAWM
ggplot(enr.specificPVML_vs_NAWM, aes(x=reorder(rownames(enr.specificPVML_vs_NAWM),-rank(NOM_pval)), y=-log10(NOM_pval),fill=-log10(NOM_pval))) + geom_col(width=.65)+ scale_fill_gradient(low="#F6BDC0",high="#DC1C13") +theme(axis.text=element_text(size=8)) + scale_x_discrete(label = function(x) stringr::str_wrap(gsub("_", " ",x), width = 30)) + labs(title = "PVML_vs_NAWM") + xlab("") + coord_flip() + theme_bw()
Common PVML_vs_NAWM & PVML_vs_WML
ggplot(enr.commonPVML_vs_NAWM.PVML_vs_WML, aes(x=reorder(rownames(enr.commonPVML_vs_NAWM.PVML_vs_WML),-rank(NOM_pval)), y=-log10(NOM_pval),fill=-log10(NOM_pval))) + geom_col(width=.65)+ scale_fill_gradient(low="#F6BDC0",high="#DC1C13") +theme(axis.text=element_text(size=8)) + scale_x_discrete(label = function(x) stringr::str_wrap(gsub("_", " ",x), width = 30)) + labs(title = "common PVML_vs_NAWM & PVML_vs_WML") + xlab("") + coord_flip() + theme_bw()
Common PVML_vs_NAWM & PVML_vs_WML & WML_vs_CL
ggplot(enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL, aes(x=reorder(rownames(enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL),-rank(NOM_pval)), y=-log10(NOM_pval),fill=-log10(NOM_pval))) + geom_col(width=.65)+ scale_fill_gradient(low="#F6BDC0",high="#DC1C13") +theme(axis.text=element_text(size=8)) + scale_x_discrete(label = function(x) stringr::str_wrap(gsub("_", " ",x), width = 30)) + labs(title = "Common PVML_vs_NAWM & PVML_vs_WML & WML_vs_CL") + xlab("") + coord_flip() + theme_bw()
Common PVML_vs_NAWM & WML_vs_CL
ggplot(enr.commonPVML_vs_NAWM.WML_vs_CL, aes(x=reorder(rownames(enr.commonPVML_vs_NAWM.WML_vs_CL),-rank(NOM_pval)), y=-log10(NOM_pval),fill=-log10(NOM_pval))) + geom_col(width=.65)+ scale_fill_gradient(low="#F6BDC0",high="#DC1C13") +theme(axis.text=element_text(size=8)) + scale_x_discrete(label = function(x) stringr::str_wrap(gsub("_", " ",x), width = 30)) + labs(title = "Common PVML_vs_NAWM & WML_vs_CL") + xlab("") + coord_flip() + theme_bw()
KEGG pathway database
enr.specificWML_vs_CL = fishKEGG$specificWML_vs_CL
enr.specificWML_vs_CL$pathway = rownames(enr.specificWML_vs_CL)
enr.specificWML_vs_CL$fdr <- as.numeric(enr.specificWML_vs_CL$fdr)
enr.specificWML_vs_CL$OR.odds.ratio <- as.numeric(enr.specificWML_vs_CL$OR.odds.ratio)
enr.specificWML_vs_CL$NOM_pval <- as.numeric(enr.specificWML_vs_CL$NOM_pval)
topspecificWML_vs_CL <- topPath(fishKEGG ,"specificWML_vs_CL", 0.5, 20)
enr.specificWML_vs_CL <- enr.specificWML_vs_CL[match(topspecificWML_vs_CL, rownames(enr.specificWML_vs_CL)),]
rownames(enr.specificWML_vs_CL) <- gsub("KEGG", "",rownames(enr.specificWML_vs_CL))
enr.specificWML_vs_CL=enr.specificWML_vs_CL[order(enr.specificWML_vs_CL$NOM_pval),]
enr.specificWML_vs_CL$comp = "specificWML_vs_CL"
enr.specificPVML_vs_NAWM = fishKEGG$specificPVML_vs_NAWM
enr.specificPVML_vs_NAWM$pathway = rownames(enr.specificPVML_vs_NAWM)
enr.specificPVML_vs_NAWM$fdr <- as.numeric(enr.specificPVML_vs_NAWM$fdr)
enr.specificPVML_vs_NAWM$OR.odds.ratio <- as.numeric(enr.specificPVML_vs_NAWM$OR.odds.ratio)
enr.specificPVML_vs_NAWM$NOM_pval <- as.numeric(enr.specificPVML_vs_NAWM$NOM_pval)
topspecificPVML_vs_NAWM <- topPath(fishKEGG ,"specificPVML_vs_NAWM", 0.5, 20)
enr.specificPVML_vs_NAWM <- enr.specificPVML_vs_NAWM[match(topspecificPVML_vs_NAWM, rownames(enr.specificPVML_vs_NAWM)),]
rownames(enr.specificPVML_vs_NAWM) <- gsub("KEGG", "",rownames(enr.specificPVML_vs_NAWM))
enr.specificPVML_vs_NAWM=enr.specificPVML_vs_NAWM[order(enr.specificPVML_vs_NAWM$NOM_pval),]
enr.specificPVML_vs_NAWM$comp = "specificPVML_vs_NAWM"
enr.commonPVML_vs_NAWM.PVML_vs_WML = fishKEGG$commonPVML_vs_NAWM.PVML_vs_WML
enr.commonPVML_vs_NAWM.PVML_vs_WML$pathway = rownames(enr.commonPVML_vs_NAWM.PVML_vs_WML)
enr.commonPVML_vs_NAWM.PVML_vs_WML$fdr <- as.numeric(enr.commonPVML_vs_NAWM.PVML_vs_WML$fdr)
enr.commonPVML_vs_NAWM.PVML_vs_WML$OR.odds.ratio <- as.numeric(enr.commonPVML_vs_NAWM.PVML_vs_WML$OR.odds.ratio)
enr.commonPVML_vs_NAWM.PVML_vs_WML$NOM_pval <- as.numeric(enr.commonPVML_vs_NAWM.PVML_vs_WML$NOM_pval)
enr.commonPVML_vs_NAWM.PVML_vs_WML=enr.commonPVML_vs_NAWM.PVML_vs_WML[order(enr.commonPVML_vs_NAWM.PVML_vs_WML$NOM_pval),]
topcommonPVML_vs_NAWM.PVML_vs_WML = subset(enr.commonPVML_vs_NAWM.PVML_vs_WML,NOM_pval<=0.1)
topcommonPVML_vs_NAWM.PVML_vs_WML = topcommonPVML_vs_NAWM.PVML_vs_WML$pathway
enr.commonPVML_vs_NAWM.PVML_vs_WML <- enr.commonPVML_vs_NAWM.PVML_vs_WML[match(topcommonPVML_vs_NAWM.PVML_vs_WML, rownames(enr.commonPVML_vs_NAWM.PVML_vs_WML)),]
rownames(enr.commonPVML_vs_NAWM.PVML_vs_WML) <- gsub("KEGG", "",rownames(enr.commonPVML_vs_NAWM.PVML_vs_WML))
enr.commonPVML_vs_NAWM.PVML_vs_WML=enr.commonPVML_vs_NAWM.PVML_vs_WML[order(enr.commonPVML_vs_NAWM.PVML_vs_WML$NOM_pval),]
enr.commonPVML_vs_NAWM.PVML_vs_WML$comp = "commonPVML_vs_NAWM & PVML_vs_WML"
enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL = fishKEGG$commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL
enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL$pathway = rownames(enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL)
enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL$fdr <- as.numeric(enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL$fdr)
enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL$OR.odds.ratio <- as.numeric(enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL$OR.odds.ratio)
enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL$NOM_pval <- as.numeric(enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL$NOM_pval)
topcommonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL <- topPath(fishKEGG ,"commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL", 0.5,20)
enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL <- enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL[match(topcommonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL, rownames(enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL)),]
rownames(enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL) <- gsub("KEGG", "",rownames(enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL))
enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL=enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL[order(enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL$NOM_pval),]
enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL$comp = "commonPVML_vs_NAWM & PVML_vs_WML & WML_vs_CL"
enr.commonPVML_vs_NAWM.WML_vs_CL = fishKEGG$commonPVML_vs_NAWM.WML_vs_CL
enr.commonPVML_vs_NAWM.WML_vs_CL$pathway = rownames(enr.commonPVML_vs_NAWM.WML_vs_CL)
enr.commonPVML_vs_NAWM.WML_vs_CL$fdr <- as.numeric(enr.commonPVML_vs_NAWM.WML_vs_CL$fdr)
enr.commonPVML_vs_NAWM.WML_vs_CL$OR.odds.ratio <- as.numeric(enr.commonPVML_vs_NAWM.WML_vs_CL$OR.odds.ratio)
enr.commonPVML_vs_NAWM.WML_vs_CL$NOM_pval <- as.numeric(enr.commonPVML_vs_NAWM.WML_vs_CL$NOM_pval)
topcommonPVML_vs_NAWM.WML_vs_CL = subset(enr.commonPVML_vs_NAWM.WML_vs_CL,NOM_pval<=0.1)
topcommonPVML_vs_NAWM.WML_vs_CL = topcommonPVML_vs_NAWM.WML_vs_CL$pathway
enr.commonPVML_vs_NAWM.WML_vs_CL <- enr.commonPVML_vs_NAWM.WML_vs_CL[match(topcommonPVML_vs_NAWM.WML_vs_CL, rownames(enr.commonPVML_vs_NAWM.WML_vs_CL)),]
rownames(enr.commonPVML_vs_NAWM.WML_vs_CL) <- gsub("KEGG", "",rownames(enr.commonPVML_vs_NAWM.WML_vs_CL))
enr.commonPVML_vs_NAWM.WML_vs_CL=enr.commonPVML_vs_NAWM.WML_vs_CL[order(enr.commonPVML_vs_NAWM.WML_vs_CL$NOM_pval),]
enr.commonPVML_vs_NAWM.WML_vs_CL$comp = "commonPVML_vs_NAWM & PVML_vs_WML"
Specific WML_vs_CL
ggplot(enr.specificWML_vs_CL, aes(x=reorder(rownames(enr.specificWML_vs_CL),-rank(NOM_pval)), y=-log10(NOM_pval),fill=-log10(NOM_pval))) + geom_col(width=.65)+ scale_fill_gradient(low="#F6BDC0",high="#DC1C13") +theme(axis.text=element_text(size=8)) + scale_x_discrete(label = function(x) stringr::str_wrap(gsub("_", " ",x), width = 30)) + labs(title = "WML_vs_CL") + xlab("") + coord_flip() + theme_bw()
Specific PVML_vs_NAWM
ggplot(enr.specificPVML_vs_NAWM, aes(x=reorder(rownames(enr.specificPVML_vs_NAWM),-rank(NOM_pval)), y=-log10(NOM_pval),fill=-log10(NOM_pval))) + geom_col(width=.65)+ scale_fill_gradient(low="#F6BDC0",high="#DC1C13") +theme(axis.text=element_text(size=8)) + scale_x_discrete(label = function(x) stringr::str_wrap(gsub("_", " ",x), width = 30)) + labs(title = "PVML_vs_NAWM") + xlab("") + coord_flip() + theme_bw()
Common PVML_vs_NAWM & PVML_vs_WML
ggplot(enr.commonPVML_vs_NAWM.PVML_vs_WML, aes(x=reorder(rownames(enr.commonPVML_vs_NAWM.PVML_vs_WML),-rank(NOM_pval)), y=-log10(NOM_pval),fill=-log10(NOM_pval))) + geom_col(width=.65)+ scale_fill_gradient(low="#F6BDC0",high="#DC1C13") +theme(axis.text=element_text(size=8)) + scale_x_discrete(label = function(x) stringr::str_wrap(gsub("_", " ",x), width = 30)) + labs(title = "common PVML_vs_NAWM & PVML_vs_WML") + xlab("") + coord_flip() + theme_bw()
Common PVML_vs_NAWM & PVML_vs_WML & WML_vs_CL
ggplot(enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL, aes(x=reorder(rownames(enr.commonPVML_vs_NAWM.PVML_vs_WML.WML_vs_CL),-rank(NOM_pval)), y=-log10(NOM_pval),fill=-log10(NOM_pval))) + geom_col(width=.65)+ scale_fill_gradient(low="#F6BDC0",high="#DC1C13") +theme(axis.text=element_text(size=8)) + scale_x_discrete(label = function(x) stringr::str_wrap(gsub("_", " ",x), width = 30)) + labs(title = "Common PVML_vs_NAWM & PVML_vs_WML & WML_vs_CL") + xlab("") + coord_flip() + theme_bw()
common PVML_vs_NAWM & WML_vs_CL
ggplot(enr.commonPVML_vs_NAWM.WML_vs_CL, aes(x=reorder(rownames(enr.commonPVML_vs_NAWM.WML_vs_CL),-rank(NOM_pval)), y=-log10(NOM_pval),fill=-log10(NOM_pval))) + geom_col(width=.65)+ scale_fill_gradient(low="#F6BDC0",high="#DC1C13") +theme(axis.text=element_text(size=8)) + scale_x_discrete(label = function(x) stringr::str_wrap(gsub("_", " ",x), width = 30)) + labs(title = "Common PVML_vs_NAWM & WML_vs_CL") + xlab("") + coord_flip() + theme_bw()
This is an analysis performed on the bulk RNA-Seq dataset from the
paper titled:
Brain macrophages acquire distinct transcriptomes in multiple
sclerosis lesions and normal appearing white matter.
The authors of this paper have sequenced 68 samples of human brain
material. Here is the paper
Abstract
Multiple sclerosis (MS) is a disease of the central nervous system
(CNS) that is characterized by inflammation and focal areas of
demyelination, ultimately resulting in axonal degradation and neuronal
loss. Several lines of evidence point towards a role for microglia and
other brain macrophages in disease initiation and progression, but
exactly how lesion formation is triggered is currently unknown. Here, we
characterized early changes in MS brain tissue through transcriptomic
analysis of normal appearing white matter (NAWM). We found that NAWM was
characterized by enriched expression of genes associated with
inflammation and cellular stress derived from brain macrophages. Single
cell RNA sequencing confirmed an early stress response in brain
macrophages in NAWM and identified specific macrophage subsets that
associate with different stages of demyelinating lesions. These early
changes associated with lesion development in MS brain tissue may
provide therapeutic targets to limit lesion progression and
demyelination.
goBP = read.gmt('/Users/macbookpro/OneDrive/Documents/UDEM/Master/BulkData/GO/c5.go.bp.v7.5.1.symbols.gmt')
metaP <- read.table("/Users/macbookpro/OneDrive/Documents/UDEM/Master/GSE179427/SraRunTable.txt", header = TRUE, sep = ",")
metaP <- data.frame(sample = metaP$Sample.Name, group=metaP$Group)
metaP <- metaP[!duplicated(metaP[ , c("sample", "group")]), ]
metaP$group <- toupper(metaP$group)
refP <- read.csv("/Users/macbookpro/OneDrive/Documents/UDEM/Master/GSE179427/ref.csv", header = TRUE, sep = ";")
refP <- data.frame(sample = refP$sample, sampleName = refP$sampleName)
refP <- merge(metaP,refP,by="sample")
countsP <- read.table("/Users/macbookpro/OneDrive/Documents/UDEM/Master/GSE179427/GSE179427_countmtx.csv", header = TRUE, sep = ";",row.names=1)
countsP[is.na(countsP)] <- 0
refPP <- data.frame(sampleName = colnames(countsP))
refPP <- merge(refPP, refP, by="sampleName")
refPP$group <- gsub('NAGM','NAWM',refPP$group)
con_colorsP = c('olivedrab2','deepskyblue','darkorange')
names(con_colorsP)=c('CONTROL','NAWM','LESION')
##remove mitochondrial gene
convP=select(org.Hs.eg.db,keys=rownames(EP$E),keytype='ENSEMBL',columns=c('GENENAME','SYMBOL'))
refGP=convP[!duplicated(convP[,1]),]
rownames(refGP)=refGP[,1]
c=subset(convP,grepl('mitochon',convP[,2]))
cc = subset(c,grepl('^MT', c[,3]))
NGMito = countsP[!rownames(countsP) %in% cc$ENSEMBL,]
## limma DEA
d0P <- DGEList(NGMito)
#d0P <- DGEList(countsP) with mitochondrial gene
d0P <- calcNormFactors(d0P)
cutoff <- 5
dropP <- which(apply(cpm(d0P), 1, max) < cutoff)
dP <- d0P[-dropP,]
metadataP <- data.frame(sampleName=rownames(dP$samples))
metadataP$group <- NA
for (i in 1:nrow(metadataP)) {
for (j in 1:nrow(refPP)) {
if(metadataP$sampleName[i]==refPP$sampleName[j]){
metadataP$group[i] = refPP$group[j]
break
}
}
}
rownames(metadataP) <- metadataP$sampleName
metadataP <- subset(metadataP, select=-c(sampleName))
mmP <- model.matrix(~0 + group:group,data=metadataP)
EP <- voom(dP, mmP, plot = F)
Principal component analysis of 68 white matter brain tissue
samples.
26 Control
31 NAWM
11 Lesion
p <- pca(EP$E, metadata = metadataP)
plot1 <- biplot(p, colby = 'group',hline = 0, vline = 0,legendPosition = 'right', lab="")
plot2<- plot1 + scale_color_manual( name= "Groups",labels = c("CONTROL","LESION","NAWM"), values= c('olivedrab2','darkorange4','goldenrod2'))
plot2
Comparisons between conditions
fitP <- lmFit(EP, mmP)
contrP <- makeContrasts(
A= groupNAWM - groupCONTROL,
B= groupLESION - groupNAWM,
C= groupLESION - groupCONTROL, levels = colnames(coef(fitP)))
tmpP <- contrasts.fit(fitP,contrP)
tmpP <- eBayes(tmpP)
res.AP <- topTable(tmpP, sort.by = "P", n = Inf, coef='A',adjust="fdr")
res.BP <- topTable(tmpP, sort.by = "P", n = Inf, coef='B',adjust="fdr")
res.CP <- topTable(tmpP, sort.by = "P", n = Inf, coef='C',adjust="fdr")
res.AP$condition = 'A: NAWM vs CWM'
res.BP$condition = 'B: WML vs NAWM'
res.CP$condition = 'C: WML vs CWM'
res.AP$geneid = rownames(res.AP)
res.BP$geneid = rownames(res.BP)
res.CP$geneid = rownames(res.CP)
res.T = rbind(res.AP,res.BP,res.CP)
res.T$symbol = refGP[res.T$geneid,3]
res.AP$symbol = refGP[res.AP$geneid,3]
res.BP$symbol = refGP[res.BP$geneid,3]
res.CP$symbol = refGP[res.CP$geneid,3]
degs.AP = subset(res.T, condition == 'A: NAWM vs CWM' & adj.P.Val<0.05 & abs(logFC)>1)$symbol
degs.BP = subset(res.T, condition == 'B: WML vs NAWM' & adj.P.Val<0.05 & abs(logFC)>1)$symbol
degs.CP = subset(res.T, condition == 'C: WML vs CWM' & adj.P.Val<0.05 & abs(logFC)>1)$symbol
res.T$sign = 'NS'
res.T[which(res.T$adj.P.Val<0.05 & res.T$logFC>1),'sign']='UP'
res.T[which(res.T$adj.P.Val<0.05 & res.T$logFC<(-1)),'sign']='DN'
res.BP$sign = 'NS'
res.BP[which(res.BP$adj.P.Val<0.05 & res.BP$logFC>1),'sign']='UP'
res.BP[which(res.BP$adj.P.Val<0.05 & res.BP$logFC<(-1)),'sign']='DN'
###
res.BP<-na.omit(res.BP[order(-res.BP$logFC),])
ggplot(res.T,aes(x=logFC,y=-log10(P.Value)))+geom_point(aes(col=sign))+theme_bw()+scale_color_manual(values=sign_cols)+geom_point(data=res.BP[1:10,], col="black") +geom_label_repel(data=res.BP[1:30,],aes(label=symbol),force=10,size = 2,fill = alpha(c("white"),0.5)) +theme(legend.position = "none",strip.background = element_rect(fill=c("grey95")))
###
res.AP<-na.omit(res.AP[order(res.AP$P.Value),])
res.BP<-na.omit(res.BP[order(res.BP$P.Value),])
res.CP<-na.omit(res.CP[order(res.CP$P.Value),])
Volcano plot with the top 10 significant genes
options(ggrepel.max.overlaps = Inf)
volcanoTop10 <- ggplot(res.T,aes(x=logFC,y=-log10(P.Value)))+geom_point(aes(col=sign))+theme_bw()+scale_color_manual(values=c('deepskyblue','grey75','tomato'))+
geom_point(data=res.AP[1:10,], col="black") +geom_label_repel(data=res.AP[1:10,],aes(label=symbol),force=10,size = 2,fill = alpha(c("white"),0.5)) +
geom_point(data=res.BP[1:10,], col="black") +geom_label_repel(data=res.BP[1:10,],aes(label=symbol),force=10,size = 2,fill = alpha(c("white"),0.5)) +
geom_point(data=res.CP[1:10,], col="black") +geom_label_repel(data=res.CP[1:10,],aes(label=symbol),force=10,size = 2,fill = alpha(c("white"),0.5)) +
theme(legend.position = "none",strip.background = element_rect(fill=c("grey95")))+ facet_wrap(~condition)
volcanoTop10
Volcano plot with genes of interest (top significant genes from
Bulk);
ICAM1,VCAM1,“DNAH5”,“CIBAR2”,“LRRIQ1”,“ODAD2”,“CD24”,“DLEC1”,“CFAP54”,“FHAD1”,“DYNLT5”,“CFAP43”,“RSPH1”,“DNAI3”
res=res[order(res$P.Value),]
genelabelsP <- c("CD24")
geneLabelsP2 <- unique(head(resA$gene_name,30))
genelabelsP <- append(genelabelsP, geneLabelsP2)
#### put gene of the public data on our comparaison
#geneLabelsPub <- unique(head(res.BP$symbol,30))
#geneLabelsPubSignificant <- subset(res.BP,sign=="UP")
#geneLabelsPubSignificant <- unique(geneLabelsPubSignificant$symbol)
#ggplot(resA,aes(x=logFC,y=-log10(P.Value)))+geom_point(aes(col=sign))+ scale_color_manual(values=sign_cols)+ geom_point(data=resA[match(geneLabelsPub, resA$gene_name),], col="black") +geom_label_repel(data=resA[match(geneLabelsPub$symbol, resA$gene_name),],aes(label=geneLabelsPub),force=10,size = 3.5,fill = alpha(c("white"),0.5),fontface = 'bold')+ theme(legend.position = "none",strip.background = element_rect(fill=c("grey95")))+theme_bw()+ggtitle("WML vs NAWM")
###
p1 = ggplot(subset(res.T,condition=="A: NAWM vs CWM"),aes(x=logFC,y=-log10(P.Value)))+geom_point(aes(col=sign))+ scale_color_manual(values=c('deepskyblue','grey75','tomato'))+ geom_point(data=res.AP[match(genelabelsP, res.AP$symbol),], col="black") +geom_label_repel(data=res.AP[match(genelabelsP, res.AP$symbol),],aes(label=genelabelsP),force=10,size = 3.5,fill = alpha(c("white"),0.5),fontface = 'bold')+ theme(legend.position = "none",strip.background = element_rect(fill=c("grey95")))+theme_bw()+ggtitle("A: NAWM vs CWM")
p2 = ggplot(subset(res.T,condition=='B: WML vs NAWM'),aes(x=logFC,y=-log10(P.Value)))+geom_point(aes(col=sign))+ scale_color_manual(values=c('deepskyblue','grey75','tomato'))+ geom_point(data=res.BP[match(genelabelsP, res.BP$symbol),], col="black") +geom_label_repel(data=res.BP[match(genelabelsP, res.BP$symbol),],aes(label=genelabelsP),force=10,size = 3.5,fill = alpha(c("white"),0.5),fontface = 'bold')+ theme(legend.position = "none",strip.background = element_rect(fill=c("grey95")))+theme_bw()+ggtitle("B: WML vs NAWM")
p3 = ggplot(subset(res.T,condition=='C: WML vs CWM'),aes(x=logFC,y=-log10(P.Value)))+geom_point(aes(col=sign))+ scale_color_manual(values=c('deepskyblue','grey75','tomato'))+ geom_point(data=res.CP[match(genelabelsP, res.CP$symbol),], col="black") +geom_label_repel(data=res.CP[match(genelabelsP, res.CP$symbol),],aes(label=genelabelsP),force=10,size = 3.5,fill = alpha(c("white"),0.5),fontface = 'bold')+ theme(legend.position = "none",strip.background = element_rect(fill=c("grey95")))+theme_bw()+ggtitle("C: WML vs CWM")
ggarrange(
p1,p2,p3, common.legend = TRUE, legend = "bottom", ncol = 3)
Boxplots of select genes demonstrating significant differential gene
expression.
#CIBAR2 <- plot.geneP("CIBAR2",cols=con_colorsP)
DNAH5 <- plot.geneP("DNAH5",cols=con_colorsP)
#irf1 <- plot.geneP("IRF1",cols=con_colorsP)
LRRIQ1 <- plot.geneP("LRRIQ1",cols=con_colorsP)
icam1 <- plot.geneP("ICAM1",cols=con_colorsP)
ODAD2 <- plot.geneP("ODAD2",cols=con_colorsP)
vcam1 <- plot.geneP("VCAM1",cols=con_colorsP)
#CD24 <- plot.geneP("CD24",cols=con_colorsP)
dlec1 <- plot.geneP("DLEC1",cols=con_colorsP)
cfap54 <- plot.geneP("CFAP54",cols=con_colorsP)
fhad1 <- plot.geneP("FHAD1",cols=con_colorsP)
dynlt5 <- plot.geneP("DYNLT5",cols=con_colorsP)
cfap43 <- plot.geneP("CFAP43",cols=con_colorsP)
rsph1 <- plot.geneP("RSPH1",cols=con_colorsP)
dnai3 <- plot.geneP("DNAI3",cols=con_colorsP)
#cxcl14 <- plot.geneP("CXCL14",cols=con_colorsP)
ggarrange(DNAH5, LRRIQ1, ODAD2, icam1, dlec1, cfap54, vcam1, fhad1, dynlt5, cfap43, rsph1, dnai3, ncol = 3, nrow = 4,align = c("hv"), common.legend = TRUE, legend="bottom")
Gene Ontology enrichment analysis (Top pathway)
Biological Process
##pathway
specificAP = as.character(na.omit(degs.AP[!degs.AP%in%degs.BP & !degs.AP%in%degs.CP]))
specificBP = as.character(na.omit(degs.BP[!degs.BP%in%degs.AP & !degs.BP%in%degs.CP]))
specificCP = as.character(na.omit(degs.CP[!degs.CP%in%degs.AP & !degs.CP%in%degs.BP]))
listP = list(specificAP=specificAP, specificBP=specificBP,specificCP=specificCP)
fishP = fisher_enrichment(listP,goBP,unique(res.T$symbol))
##top10 pathway BP
tabAP <- fishP$specificAP
tabAP$fdr <- as.numeric(tabAP$fdr)
tabAP$OR.odds.ratio <- as.numeric(tabAP$OR.odds.ratio)
tabAP$NOM_pval <- as.numeric(tabAP$NOM_pval)
topAP <- topPath(fishP ,"specificAP", 0.5, 14)
tabAP1 <- tabAP[match(topAP, rownames(tabAP)),]
rownames(tabAP1) <- gsub("GOBP_", "",rownames(tabAP1))
rownames(tabAP1) <- gsub("_", " ",rownames(tabAP1))
rownames(tabAP) <- gsub("GOBP_", "",rownames(tabAP))
rownames(tabAP) <- gsub("_", " ",rownames(tabAP))
tabBP <- fishP$specificBP
tabBP$fdr <- as.numeric(tabBP$fdr)
tabBP$OR.odds.ratio <- as.numeric(tabBP$OR.odds.ratio)
tabBP$NOM_pval <- as.numeric(tabBP$NOM_pval)
topBP <- topPath(fishP ,"specificBP", 0.5, 14)
tabBP1 <- tabBP[match(topBP, rownames(tabBP)),]
rownames(tabBP1) <- gsub("GOBP_", "",rownames(tabBP1))
rownames(tabBP1) <- gsub("_", " ",rownames(tabBP1))
rownames(tabBP) <- gsub("GOBP_", "",rownames(tabBP))
rownames(tabBP) <- gsub("_", " ",rownames(tabBP))
tabCP <- fishP$specificCP
tabCP$fdr <- as.numeric(tabCP$fdr)
tabCP$OR.odds.ratio <- as.numeric(tabCP$OR.odds.ratio)
tabCP$NOM_pval <- as.numeric(tabCP$NOM_pval)
topCP <- topPath(fishP ,"specificCP", 0.5, 14)
tabCP1 <- tabCP[match(topCP, rownames(tabCP)),]
rownames(tabCP1) <- gsub("GOBP_", "",rownames(tabCP1))
rownames(tabCP1) <- gsub("_", " ",rownames(tabCP1))
rownames(tabCP) <- gsub("GOBP_", "",rownames(tabCP))
rownames(tabCP) <- gsub("_", " ",rownames(tabCP))
Top 10 pathway CWM vs NAWM
ggplot(tabAP1, aes(x=reorder(rownames(tabAP1),-rank(NOM_pval)), y=-log10(NOM_pval),fill=-log10(NOM_pval))) +geom_col(width=.65)+ scale_fill_gradient(low="#F6BDC0",high="#DC1C13") +theme(axis.text=element_text(size=8)) + scale_x_discrete(label = function(x) stringr::str_wrap(gsub("_", " ",x), width = 30)) + labs(title = "CWM vs NAWM", subtitle = "GO Biological Process 2021") + xlab("") + coord_flip() + theme_bw()+ theme(axis.text = element_text(face="bold"))
Top 10 pathway NAWM vs WML
ggplot(tabBP1, aes(x=reorder(rownames(tabBP1),-rank(NOM_pval)), y=-log10(NOM_pval),fill=-log10(NOM_pval))) +geom_col(width=.65)+ scale_fill_gradient(low="#F6BDC0",high="#DC1C13")+theme(axis.text=element_text(size=8)) + scale_x_discrete(label = function(x) stringr::str_wrap(gsub("_", " ",x), width = 30)) + xlab("")+ labs(title = "NAWM vs WML", subtitle = "GO Biological Process 2021") + coord_flip()+ theme_bw()+ theme(axis.text = element_text(face="bold"))
Top 10 pathway CWM vs WML
ggplot(tabCP1, aes(x=reorder(rownames(tabCP1),-rank(NOM_pval)), y=-log10(NOM_pval),fill=-log10(NOM_pval))) +geom_col(width=.65)+ scale_fill_gradient(low="#F6BDC0",high="#DC1C13")+theme(axis.text=element_text(size=8)) + scale_x_discrete(label = function(x) stringr::str_wrap(gsub("_", " ",x), width = 30)) + xlab("")+ labs( title = "CWM vs WML", subtitle = "GO Molecular Function 2021") + coord_flip()+theme_bw()+ theme(axis.text = element_text(face="bold"))
Molecular Function
##pathway
specificAP = as.character(na.omit(degs.AP[!degs.AP%in%degs.BP & !degs.AP%in%degs.CP]))
specificBP = as.character(na.omit(degs.BP[!degs.BP%in%degs.AP & !degs.BP%in%degs.CP]))
specificCP = as.character(na.omit(degs.CP[!degs.CP%in%degs.AP & !degs.CP%in%degs.BP]))
listP = list(specificAP=specificAP, specificBP=specificBP,specificCP=specificCP)
fishP = fisher_enrichment(listP,mf,unique(res.T$symbol))
##top10 pathway MF
tabAP <- fishP$specificAP
tabAP$fdr <- as.numeric(tabAP$fdr)
tabAP$OR.odds.ratio <- as.numeric(tabAP$OR.odds.ratio)
tabAP$NOM_pval <- as.numeric(tabAP$NOM_pval)
topAP <- topPath(fishP ,"specificAP", 0.5, 12)
tabAP1 <- tabAP[match(topAP, rownames(tabAP)),]
rownames(tabAP1) <- gsub("GOMF_", "",rownames(tabAP1))
rownames(tabAP1) <- gsub("_", " ",rownames(tabAP1))
rownames(tabAP) <- gsub("GOMF_", "",rownames(tabAP))
rownames(tabAP) <- gsub("_", " ",rownames(tabAP))
tabBP <- fishP$specificBP
tabBP$fdr <- as.numeric(tabBP$fdr)
tabBP$OR.odds.ratio <- as.numeric(tabBP$OR.odds.ratio)
tabBP$NOM_pval <- as.numeric(tabBP$NOM_pval)
tabBP=tabBP[order(tabBP$NOM_pval),]
topBP = subset(tabBP,NOM_pval<=0.05)
topBP$pathway = rownames(topBP)
tabBP1 <- tabBP[match(rownames(topBP), rownames(tabBP)),]
tabBP1 <- tabBP1[-c(8, 9, 14, 15), ]
tabBP1 <- tabBP1[1:12,]
rownames(tabBP1) <- gsub("GOMF_", "",rownames(tabBP1))
rownames(tabBP1) <- gsub("_", " ",rownames(tabBP1))
rownames(tabBP) <- gsub("GOMF_", "",rownames(tabBP))
rownames(tabBP) <- gsub("_", " ",rownames(tabBP))
tabCP <- fishP$specificCP
tabCP$fdr <- as.numeric(tabCP$fdr)
tabCP$OR.odds.ratio <- as.numeric(tabCP$OR.odds.ratio)
tabCP$NOM_pval <- as.numeric(tabCP$NOM_pval)
topCP <- topPath(fishP ,"specificCP", 0.5, 12)
tabCP1 <- tabCP[match(topCP, rownames(tabCP)),]
rownames(tabCP1) <- gsub("GOMF_", "",rownames(tabCP1))
rownames(tabCP1) <- gsub("_", " ",rownames(tabCP1))
rownames(tabCP) <- gsub("GOMF_", "",rownames(tabCP))
rownames(tabCP) <- gsub("_", " ",rownames(tabCP))
Top 10 pathway CWM vs NAWM
ggplot(tabAP1, aes(x=reorder(rownames(tabAP1),-rank(NOM_pval)), y=-log10(NOM_pval),fill=-log10(NOM_pval))) +geom_col(width=.65)+ scale_fill_gradient(low="#F6BDC0",high="#DC1C13") +theme(axis.text=element_text(size=8)) + scale_x_discrete(label = function(x) stringr::str_wrap(gsub("_", " ",x), width = 30)) + labs(title = "CWM vs NAWM", subtitle = "GO Molecular Function 2021") + xlab("") + coord_flip() + theme_bw()+ theme(axis.text = element_text(face="bold"))
Top 10 pathway NAWM vs WML
ggplot(tabBP1, aes(x=reorder(rownames(tabBP1),-rank(NOM_pval)), y=-log10(NOM_pval),fill=-log10(NOM_pval))) +geom_col(width=.65)+ scale_fill_gradient(low="#F6BDC0",high="#DC1C13")+theme(axis.text=element_text(size=8)) + scale_x_discrete(label = function(x) stringr::str_wrap(gsub("_", " ",x), width = 30)) + xlab("")+ labs(title = "NAWM vs WML", subtitle = "GO Molecular Function 2021") + coord_flip()+ theme_bw()+ theme(axis.text = element_text(face="bold"))
Top 10 pathway CWM vs WML
ggplot(tabCP1, aes(x=reorder(rownames(tabCP1),-rank(NOM_pval)), y=-log10(NOM_pval),fill=-log10(NOM_pval))) +geom_col(width=.65)+ scale_fill_gradient(low="#F6BDC0",high="#DC1C13")+theme(axis.text=element_text(size=8)) + scale_x_discrete(label = function(x) stringr::str_wrap(gsub("_", " ",x), width = 30)) + xlab("")+ labs( title = "CWM vs WML", subtitle = "GO Molecular Function 2021") + coord_flip()+theme_bw()+ theme(axis.text = element_text(face="bold"))
Transcription factor targets
##pathway
specificAP = as.character(na.omit(degs.AP[!degs.AP%in%degs.BP & !degs.AP%in%degs.CP]))
specificBP = as.character(na.omit(degs.BP[!degs.BP%in%degs.AP & !degs.BP%in%degs.CP]))
specificCP = as.character(na.omit(degs.CP[!degs.CP%in%degs.AP & !degs.CP%in%degs.BP]))
listP = list(specificAP=specificAP, specificBP=specificBP,specificCP=specificCP)
fishP = fisher_enrichment(listP,tft,unique(res.T$symbol))
##top10 pathway TFT
tabAP <- fishP$specificAP
tabAP$fdr <- as.numeric(tabAP$fdr)
tabAP$OR.odds.ratio <- as.numeric(tabAP$OR.odds.ratio)
tabAP$NOM_pval <- as.numeric(tabAP$NOM_pval)
tabAP=tabAP[order(tabAP$NOM_pval),]
topAP = subset(tabAP,NOM_pval<=0.05)
topAP$pathway = rownames(topAP)
tabAP1 <- tabAP[match(rownames(topAP), rownames(tabAP)),]
tabAP1 <- tabAP1[1:12,]
rownames(tabAP1) <- gsub("_", " ",rownames(tabAP1))
rownames(tabAP) <- gsub("_", " ",rownames(tabAP))
tabBP <- fishP$specificBP
tabBP$fdr <- as.numeric(tabBP$fdr)
tabBP$OR.odds.ratio <- as.numeric(tabBP$OR.odds.ratio)
tabBP$NOM_pval <- as.numeric(tabBP$NOM_pval)
tabBP=tabBP[order(tabBP$NOM_pval),]
topBP = subset(tabBP,NOM_pval<=0.05)
topBP$pathway = rownames(topBP)
tabBP1 <- tabBP[match(rownames(topBP), rownames(tabBP)),]
tabBP1 <- tabBP1[1:12,]
rownames(tabBP1) <- gsub("_", " ",rownames(tabBP1))
rownames(tabBP) <- gsub("_", " ",rownames(tabBP))
tabCP <- fishP$specificCP
tabCP$fdr <- as.numeric(tabCP$fdr)
tabCP$OR.odds.ratio <- as.numeric(tabCP$OR.odds.ratio)
tabCP$NOM_pval <- as.numeric(tabCP$NOM_pval)
topCP <- topPath(fishP ,"specificCP", 0.5, 12)
tabCP1 <- tabCP[match(topCP, rownames(tabCP)),]
rownames(tabCP1) <- gsub("_", " ",rownames(tabCP1))
rownames(tabCP) <- gsub("_", " ",rownames(tabCP))
Top 10 pathway CWM vs NAWM
ggplot(tabAP1, aes(x=reorder(rownames(tabAP1),-rank(NOM_pval)), y=-log10(NOM_pval),fill=-log10(NOM_pval))) +geom_col(width=.65)+ scale_fill_gradient(low="#F6BDC0",high="#DC1C13") +theme(axis.text=element_text(size=8)) + scale_x_discrete(label = function(x) stringr::str_wrap(gsub("_", " ",x), width = 30)) + labs(title = "CWM vs NAWM", subtitle = "GO Transcription factor targets 2021") + xlab("") + coord_flip() + theme_bw()
Top 10 pathway NAWM vs WML
ggplot(tabBP1, aes(x=reorder(rownames(tabBP1),-rank(NOM_pval)), y=-log10(NOM_pval),fill=-log10(NOM_pval))) +geom_col(width=.65)+ scale_fill_gradient(low="#F6BDC0",high="#DC1C13")+theme(axis.text=element_text(size=8)) + scale_x_discrete(label = function(x) stringr::str_wrap(gsub("_", " ",x), width = 30)) + xlab("")+ labs(title = "NAWM vs WML", subtitle = "GO Transcription factor targets 2021") + coord_flip()+ theme_bw()
Top 10 pathway CWM vs WML
ggplot(tabCP1, aes(x=reorder(rownames(tabCP1),-rank(NOM_pval)), y=-log10(NOM_pval),fill=-log10(NOM_pval))) +geom_col(width=.65)+ scale_fill_gradient(low="#F6BDC0",high="#DC1C13")+theme(axis.text=element_text(size=8)) + scale_x_discrete(label = function(x) stringr::str_wrap(gsub("_", " ",x), width = 30)) + xlab("")+ labs( title = "CWM vs WML", subtitle = "GO Transcription factor targets 2021") + coord_flip()+theme_bw()
KEGG pathway database
##pathway
specificAP = as.character(na.omit(degs.AP[!degs.AP%in%degs.BP & !degs.AP%in%degs.CP]))
specificBP = as.character(na.omit(degs.BP[!degs.BP%in%degs.AP & !degs.BP%in%degs.CP]))
specificCP = as.character(na.omit(degs.CP[!degs.CP%in%degs.AP & !degs.CP%in%degs.BP]))
listP = list(specificAP=specificAP, specificBP=specificBP,specificCP=specificCP)
fishP = fisher_enrichment(listP,kegg,unique(res.T$symbol))
##top10 pathway KEGG
tabAP <- fishP$specificAP
tabAP$fdr <- as.numeric(tabAP$fdr)
tabAP$OR.odds.ratio <- as.numeric(tabAP$OR.odds.ratio)
tabAP$NOM_pval <- as.numeric(tabAP$NOM_pval)
tabAP=tabAP[order(tabAP$NOM_pval),]
topAP = subset(tabAP,NOM_pval<=0.17)
topAP$pathway = rownames(topAP)
tabAP1 <- tabAP[match(rownames(topAP), rownames(tabAP)),]
rownames(tabAP1) <- gsub("KEGG", "",rownames(tabAP1))
rownames(tabAP1) <- gsub("_", " ",rownames(tabAP1))
rownames(tabAP) <- gsub("KEGG", "",rownames(tabAP))
rownames(tabAP) <- gsub("_", " ",rownames(tabAP))
tabBP <- fishP$specificBP
tabBP$fdr <- as.numeric(tabBP$fdr)
tabBP$OR.odds.ratio <- as.numeric(tabBP$OR.odds.ratio)
tabBP$NOM_pval <- as.numeric(tabBP$NOM_pval)
tabBP=tabBP[order(tabBP$NOM_pval),]
topBP = subset(tabBP,NOM_pval<=0.3)
topBP$pathway = rownames(topBP)
tabBP1 <- tabBP[match(rownames(topBP), rownames(tabBP)),]
tabBP1 <- tabBP1[1:10,]
rownames(tabBP1) <- gsub("KEGG", "",rownames(tabBP1))
rownames(tabBP1) <- gsub("_", " ",rownames(tabBP1))
rownames(tabBP) <- gsub("KEGG", "",rownames(tabBP))
rownames(tabBP) <- gsub("_", " ",rownames(tabBP))
tabCP <- fishP$specificCP
tabCP$fdr <- as.numeric(tabCP$fdr)
tabCP$OR.odds.ratio <- as.numeric(tabCP$OR.odds.ratio)
tabCP$NOM_pval <- as.numeric(tabCP$NOM_pval)
topCP <- topPath(fishP ,"specificCP", 0.5, 12)
tabCP1 <- tabCP[match(topCP, rownames(tabCP)),]
rownames(tabCP1) <- gsub("KEGG", "",rownames(tabCP1))
rownames(tabCP1) <- gsub("_", " ",rownames(tabCP1))
rownames(tabCP) <- gsub("KEGG", "",rownames(tabCP))
rownames(tabCP) <- gsub("_", " ",rownames(tabCP))
Top 10 pathway CWM vs NAWM
ggplot(tabAP1, aes(x=reorder(rownames(tabAP1),-rank(NOM_pval)), y=-log10(NOM_pval),fill=-log10(NOM_pval))) +geom_col(width=.65)+ scale_fill_gradient(low="#F6BDC0",high="#DC1C13") +theme(axis.text=element_text(size=8)) + scale_x_discrete(label = function(x) stringr::str_wrap(gsub("_", " ",x), width = 30)) + labs(title = "CWM vs NAWM", subtitle = "GO KEGG pathway database 2021") + xlab("") + coord_flip() + theme_bw()
Top 10 pathway NAWM vs WML
ggplot(tabBP1, aes(x=reorder(rownames(tabBP1),-rank(NOM_pval)), y=-log10(NOM_pval),fill=-log10(NOM_pval))) +geom_col(width=.65)+ scale_fill_gradient(low="#F6BDC0",high="#DC1C13")+theme(axis.text=element_text(size=8)) + scale_x_discrete(label = function(x) stringr::str_wrap(gsub("_", " ",x), width = 30)) + xlab("")+ labs(title = "NAWM vs WML", subtitle = "GO KEGG pathway database 2021") + coord_flip()+ theme_bw()
Top 10 pathway CWM vs WML
ggplot(tabCP1, aes(x=reorder(rownames(tabCP1),-rank(NOM_pval)), y=-log10(NOM_pval),fill=-log10(NOM_pval))) +geom_col(width=.65)+ scale_fill_gradient(low="#F6BDC0",high="#DC1C13")+theme(axis.text=element_text(size=8)) + scale_x_discrete(label = function(x) stringr::str_wrap(gsub("_", " ",x), width = 30)) + xlab("")+ labs( title = "CWM vs WML", subtitle = "GO KEGG pathway database 2021") + coord_flip()+theme_bw()
LS0tCnRpdGxlOiAiQnVsayBhbmFseXNpcyBvZiBNUyBsZXNpb25zIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpUaGlzIGlzIGFuIGFuYWx5c2lzIHBlcmZvcm1lZCBvbiB0aGUgYnVsayBSTkEtU2VxIGRhdGFzZXQKClRoZSB3b3JrZmxvdyBpcyBhcyBmb2xsb3dzOiAgCjEuIEluc3BlY3QgdmFyaWFuY2UgaW4gdGhlIGRhdGFzZXQgKEZpbHRlcmluZywgTm9ybWFsaXphdGlvbiwgUENBKSAgCjIuIFBlcmZvcm0gZGlmZmVyZW50aWFsIGV4cHJlc3Npb24gYW5hbHlzaXMgKFVzaW5nIGxpbW1hKSAgCjMuIEFubm90YXRlIGJpb2xvZ2ljYWwgc2lnbmF0dXJlcyBmb3VuZCBieSBERUEgKEdTRUEpICAKCmBgYHtyICBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmxpYnJhcnkoZWRnZVIpCmxpYnJhcnkoZmdzZWEpCmxpYnJhcnkocXVzYWdlKQpsaWJyYXJ5KERFU2VxMikKbGlicmFyeShvcmcuSHMuZWcuZGIpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShlbnJpY2hSKQpsaWJyYXJ5KFZlbm5EaWFncmFtKQpsaWJyYXJ5KGdncHVicikKbGlicmFyeShnZ3JlcGVsKQpsaWJyYXJ5KFBDQXRvb2xzKQpsaWJyYXJ5KFJDb2xvckJyZXdlcikKbGlicmFyeShnZ2lyYXBoKQpsaWJyYXJ5KFVwU2V0UikKbGlicmFyeShyaGFuZHNvbnRhYmxlKQpsaWJyYXJ5KG5sb3B0cikKbGlicmFyeShnZ1Zlbm5EaWFncmFtKQpsaWJyYXJ5KEJpb2NNYW5hZ2VyKQpsaWJyYXJ5KHN0cmluZ3IpCmxpYnJhcnkoa25pdHIpCmBgYAojIyMgQ291bnRzIGxpc3QKYGBge3IgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCByZXN1bHRzPSdhc2lzJ30KZGF0ID0gcmVhZC5jc3YoJy9Vc2Vycy9tYWNib29rcHJvL09uZURyaXZlL0RvY3VtZW50cy9VREVNL01hc3Rlci9CdWxrRGF0YS9kYXRhL21lcmdlZF9jb3VudHMuYXByMjAyMi5jc3YnLHJvdy5uYW1lcz0xKQprbml0cjo6a2FibGUoZGF0WzE6NiwgMToxMl0sIGNhcHRpb24gPSJBIEtuaXRyIGthYmxlIikKYGBgCgojIyMgTWV0YSBkYXRhCmBgYHtyIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcmVzdWx0cz0nYXNpcyd9Cm1ldGEgPSByZWFkLnRhYmxlKCcvVXNlcnMvbWFjYm9va3Byby9PbmVEcml2ZS9Eb2N1bWVudHMvVURFTS9NYXN0ZXIvQnVsa0RhdGEvZGF0YS9tZXRhX2RhdGEuYXByMjAyMi5jc3YnLHJvdy5uYW1lcz0xLHNlcCA9ICIsIikKbmFtZXMobWV0YSlbbmFtZXMobWV0YSkgPT0gInR5cGUiXSA8LSAibGVzaW9uX3R5cGUiCm1ldGEkc2V4ID0gJ00nCm1ldGFbd2hpY2gobWV0YSRzYW1wbGU9PSJBQjIwMyIpLF0kc2V4ID0gJ0YnCm1ldGEudG1wIDwtIG1ldGFbYygyLDcsMTAsMTEsMTIsMTMpXQprbml0cjo6a2FibGUobWV0YS50bXBbMTo4LF0sIGNhcHRpb24gPSJBIEtuaXRyIGthYmxlIikKYGBgCgoKRGVmaW5lIGZ1bmN0aW9ucyBmb3IgdGhlIGFuYWx5c2lzOgotIGZpbmRfZW5yaWNobWVudHMoKTogRm9yIGEgZ2l2ZW4gY29tcGFyaXNvbiAoREVBKSBleHRyYWN0IGVucmljaG1lbnRzIGZvciBHTyhCUCksIEdPKE1GKSwgS0VHRyBhbmQgVEZUICAKLSBmaXNoZXJfZW5yaWNobWVudCgpOiBQZXJmb3JtIGFuIGVucmljaG1lbnQgb2YgZ2VuZXNldHMgdXNpbmcgYSBmaXNoZXIgdGVzdCBhcHByb2FjaCAKLSBwbG90LmdlbmUoKTogUGxvdCBnZW5lIGV4cHJlc3Npb24gZm9yIGEgZ2l2ZW4gZ2VuZSBhY3Jvc3MgY29uZGl0aW9ucy4gCgpUaGUgZ210IGZpbGVzIGNvbnRhaW4gdGhlIGdlbmVzZXRzIGZvciAqR1NFQSoKCmBgYHtyIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcGFnZWQucHJpbnQ9VFJVRX0KZ28gPSByZWFkLmdtdCgnL1VzZXJzL21hY2Jvb2twcm8vT25lRHJpdmUvRG9jdW1lbnRzL1VERU0vTWFzdGVyL0J1bGtEYXRhL0dPL2M1LmdvLmJwLnY3LjUuMS5zeW1ib2xzLmdtdCcpCm1mID0gcmVhZC5nbXQoJy9Vc2Vycy9tYWNib29rcHJvL09uZURyaXZlL0RvY3VtZW50cy9VREVNL01hc3Rlci9CdWxrRGF0YS9HTy9jNS5nby5tZi52Ny41LjEuc3ltYm9scy5nbXQnKQprZWdnID0gcmVhZC5nbXQoJy9Vc2Vycy9tYWNib29rcHJvL09uZURyaXZlL0RvY3VtZW50cy9VREVNL01hc3Rlci9CdWxrRGF0YS9HTy9jMi5jcC5rZWdnLnY3LjUuMS5zeW1ib2xzLmdtdCcpCnRmdCA9IHJlYWQuZ210KCcvVXNlcnMvbWFjYm9va3Byby9PbmVEcml2ZS9Eb2N1bWVudHMvVURFTS9NYXN0ZXIvQnVsa0RhdGEvR08vYzMudGZ0LnY3LjUuMS5zeW1ib2xzLmdtdCcpCgpzaWduX2NvbHM9YyhETj0nZGVlcHNreWJsdWUnLE5TPSdncmV5ODAnLFVQPSd0b21hdG8nKQoKcGxvdC5nZW5lIDwtIGZ1bmN0aW9uKHgpewogIGdlbmVfaWQgPSByb3duYW1lcyhzdWJzZXQocmVzQSxnZW5lX25hbWU9PXgpKVsxXQogIG1ldGEkZ2VuZSA9IHkkRVtnZW5lX2lkLHJvd25hbWVzKG1ldGEpXQogIGdncGxvdChzdWJzZXQobWV0YSxsZXNpb25fdHlwZSE9Ik1peGVkIiksYWVzKGxlc2lvbl90eXBlLGdlbmUpKStnZW9tX2JveHBsb3QoKStnZW9tX3BvaW50KGFlcyhjb2w9c2FtcGxlKSkrdGhlbWVfYncoKSsgZ2d0aXRsZSh4KQp9CgojIHBsb3QuZ2VuZVAoIlNPRDIiLGNvbHM9Y29uX2NvbG9yc1ApCnBsb3QuZ2VuZVAgPC0gZnVuY3Rpb24oc3ltYm9sLHg9J2dyb3VwJyxjb2xzKXsKICAKICBnZW5laWQgPSBzdWJzZXQoY29udlAsU1lNQk9MPT1zeW1ib2wpJEVOU0VNQkwKICBtZXRhLnRtcCA9IG1ldGFkYXRhUAogIG1ldGEudG1wJGV4cHIgPSBFUCRFW2dlbmVpZCxyb3duYW1lcyhtZXRhLnRtcCldCiAgbWV0YS50bXAkZ3JvdXAgPC0gZmFjdG9yKG1ldGEudG1wJGdyb3VwICwgbGV2ZWxzPWMoJ0NPTlRST0wnLCdOQVdNJywnTEVTSU9OJykpCiAgcGwgPSBnZ3Bsb3QobWV0YS50bXAsYWVzKGdyb3VwLGV4cHIsZmlsbD1ncm91cCkpK2dlb21fYm94cGxvdCh3aWR0aD0uNzUsc2l6ZT0uNzUpK3RoZW1lX2J3KCkrc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWNvbHMpKwogICAgbGFicyh0aXRsZSA9IHN5bWJvbCwgeCA9ICJHcm91cCIsIHkgPSAiRXhwciIpICsgeGxhYigiIikgKyB5bGFiKCIiKQogIAogIHJldHVybihwbCkKfQoKZmlzaGVyX2VucmljaG1lbnQ8LWZ1bmN0aW9uKGNsdXN0ZXJfbWFya2VycyxwYXRod2F5LHVuaXZlcnNlLHBhdGh3YXlfbmFtZSl7CmVucmljaG1lbnRfdGFibGVzPWxpc3QoKSAKICBmb3IoY2x1c3RlciBpbiAxOmxlbmd0aChjbHVzdGVyX21hcmtlcnMpKXsKICAgIGNsdXN0ZXJfbmFtZT1uYW1lcyhjbHVzdGVyX21hcmtlcnMpW2NsdXN0ZXJdCiAgICBvdXRwdXQgPC0gbGFwcGx5KHBhdGh3YXksIGZ1bmN0aW9uKHgpIHsKICAgIGZyZXEudGFibGUgPC0gdGFibGUoZmFjdG9yKHVuaXZlcnNlICVpbiUgYXMuY2hhcmFjdGVyKGNsdXN0ZXJfbWFya2Vyc1tbY2x1c3Rlcl1dKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYyhUUlVFLEZBTFNFKSksIAogICAgICAgICAgICAgICAgICAgIAkgIGZhY3Rvcih1bml2ZXJzZSAlaW4lIHgsIAogICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoVFJVRSxGQUxTRSkpKQoKICAgICAgZml0IDwtIGZpc2hlci50ZXN0KGZyZXEudGFibGUsIGFsdGVybmF0aXZlID0gImdyZWF0ZXIiKQogICAgICBpbnRlclNlY3Rpb24gPC0gaW50ZXJzZWN0KGNsdXN0ZXJfbWFya2Vyc1tbY2x1c3Rlcl1dLCB4KQogICAgICBpbnRlclNlY3Rpb24gPC0gcGFzdGUoaW50ZXJTZWN0aW9uLCBjb2xsYXBzZSA9ICIsIikKICAgICAgcmV0dXJuKHZhbHVlID0gYyhOT01fcHZhbCA9IGZpdCRwLnZhbHVlLCBJTlRFUlNFQ1QgPSBpbnRlclNlY3Rpb24sIk9SIj1maXQkZXN0aW1hdGUpKX0pCiAgICAKICAgIHRlcm1fbmFtZXM9Y2hhcmFjdGVyKCkKICAgIGZvciAocGF0aHdheS50ZXJtIGluIDE6bGVuZ3RoKG91dHB1dCkpewogICAgICB0ZXJtX25hbWVzW3BhdGh3YXkudGVybV09cGF0aHdheVtbcGF0aHdheS50ZXJtXV1bMV0KICAgIH0KICAKICAgIHJlc3VsdHM9ZGF0YS5mcmFtZShkby5jYWxsKCJyYmluZCIsb3V0cHV0KSkKICAgIHJlc3VsdHMkZmRyPXAuYWRqdXN0KGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKHJlc3VsdHMkTk9NX3B2YWwpKSxtZXRob2QgPSAiQkgiKQogICAgcmVzdWx0cz1yZXN1bHRzW29yZGVyKHJlc3VsdHMkZmRyKSxdCiAgICBlbnJpY2htZW50X3RhYmxlc1tbY2x1c3Rlcl9uYW1lXV09cmVzdWx0cwogIH0KCiAgcmV0dXJuKGVucmljaG1lbnRfdGFibGVzKQp9CgpmaW5kX2VucmljaG1lbnRzPC1mdW5jdGlvbihyZXNBLG49NSxzaG93PSdib3RoJyl7CiAgcmVzQS50ID0gcmVzQSR0CiAgbmFtZXMocmVzQS50KT1yZXNBJGdlbmVfbmFtZSAKICBpZihzaG93PT0ndXAnKXsKICAgIHJlc0EuYnAgPSBzdWJzZXQoZmdzZWEoZ28scmVzQS50KSxORVM+MCkKICAgIHJlc0EubWYgPSBzdWJzZXQoZmdzZWEobWYscmVzQS50KSxORVM+MCkKICAgIHJlc0Eua2VnZz0gc3Vic2V0KGZnc2VhKGtlZ2cscmVzQS50KSxORVM+MCkKICAgIHJlc0EudGZ0PSBzdWJzZXQoZmdzZWEodGZ0LHJlc0EudCksTkVTPjApCiAgfWVsc2UgaWYoc2hvdz09J2Rvd24nKXsKICAgIHJlc0EuYnAgPSBzdWJzZXQoZmdzZWEoZ28scmVzQS50KSxORVM8MCkKICAgIHJlc0EubWYgPSBzdWJzZXQoZmdzZWEobWYscmVzQS50KSxORVM8MCkKICAgIHJlc0Eua2VnZz0gc3Vic2V0KGZnc2VhKGtlZ2cscmVzQS50KSxORVM8MCkgICAKICAgIHJlc0EudGZ0PSBzdWJzZXQoZmdzZWEodGZ0LHJlc0EudCksTkVTPDApCiAgICAKICB9ZWxzZXsKICAgIHJlc0EuYnAgPSBmZ3NlYShnbyxyZXNBLnQpCiAgICByZXNBLm1mID0gZmdzZWEobWYscmVzQS50KQogICAgcmVzQS5rZWdnPSBmZ3NlYShrZWdnLHJlc0EudCkgICAKICAgIHJlc0EudGZ0PSBzdWJzZXQoZmdzZWEodGZ0LHJlc0EudCkpCiAgfQogIAogIHJlc0EuYnAkR08gPSAnQlAnCiAgcmVzQS5tZiRHTyA9ICdNRicKICByZXNBLmtlZ2ckR08gPSAnS0VHRycKICBvdXQ9bGlzdChlbnI9bGlzdChicD1yZXNBLmJwLG1mPXJlc0EubWYsa2VnZz1yZXNBLmtlZ2csdGZ0PXJlc0EudGZ0KSkKICAKICBlbnIgPSByYmluZCgKICAgIGhlYWQocmVzQS5icFtvcmRlcihyZXNBLmJwJHBhZGopLF0sbiksCiAgICBoZWFkKHJlc0EubWZbb3JkZXIocmVzQS5tZiRwYWRqKSxdLG4pLAogICAgaGVhZChyZXNBLmtlZ2dbb3JkZXIocmVzQS5rZWdnJHBhZGopLF0sbikKICApCiAgZW5yPWRhdGEuZnJhbWUoZW5yKQogIGVuciRwYXRod2F5PWdzdWIoJ18nLCcgJyxnc3ViKCdHT198S0VHR18nLCcnLGVuciRwYXRod2F5KSkKICBlbnIkcGF0aHdheT1mYWN0b3IoZW5yJHBhdGh3YXksbGV2ZWxzPWFzLmNoYXJhY3RlcihlbnJbb3JkZXIoZW5yJEdPLGVuciRORVMpLCdwYXRod2F5J10pKQogIHA9Z2dwbG90KGVucixhZXMocGF0aHdheSxORVMsZmlsbD1HTykpK2dlb21fY29sKHdpZHRoPS42LGFscGhhPS42KStnZW9tX2NvbCh3aWR0aD0uNixmaWxsPU5BLGFlcyhjb2w9R08pKStjb29yZF9mbGlwKCkrdGhlbWVfYncoKStnZW9tX3ZsaW5lKHhpbnRlcmNlcHQ9YyhuLG4qMikrLjUsbGluZXR5cGU9J2Rhc2hlZCcpK2dlb21faGxpbmUoeWludGVyY2VwdD0wKQogIG91dCRwbG90PXAKICByZXR1cm4ob3V0KQp9CgojI3RvcCBwYXRod2F5CnRvcFBhdGg8LSBmdW5jdGlvbihmaXNoICxzcGVjaWZpYywgcCAsbil7CiAgbD1uKjIwCiAgcmVzdWx0IDwtIG1hdHJpeChOQSwgbCwgbCkKICAKICBjb2xuYW1lcyhyZXN1bHQpIDwtIHJvd25hbWVzKHJlc3VsdCkgPC0gcm93bmFtZXMoZ2V0RWxlbWVudChmaXNoLCBzcGVjaWZpYykpWzE6bF0KICBmb3IoaSBpbiAxOmwpewogICAgZm9yKGogaW4gMTpsKXsKICAgICAgbWlubGlzdCA9IDAKICAgICAgaWYobGVuZ3RoKHVubGlzdChzdHJzcGxpdChmaXNoW1tzcGVjaWZpY11dW1siSU5URVJTRUNUIl1dW2ldLCBzcGxpdCA9ICIsIikpKT49bGVuZ3RoKHVubGlzdChzdHJzcGxpdChmaXNoW1tzcGVjaWZpY11dW1siSU5URVJTRUNUIl1dW2pdLCBzcGxpdCA9ICIsIikpKSkgbWlubGlzdD1sZW5ndGgodW5saXN0KHN0cnNwbGl0KGZpc2hbW3NwZWNpZmljXV1bWyJJTlRFUlNFQ1QiXV1bal0sIHNwbGl0ID0gIiwiKSkpIAogICAgICBlbHNlIG1pbmxpc3Q9bGVuZ3RoKHVubGlzdChzdHJzcGxpdChmaXNoW1tzcGVjaWZpY11dW1siSU5URVJTRUNUIl1dW2ldLCBzcGxpdCA9ICIsIikpKQogICAgICByZXN1bHRbaSwgal0gPC0gbGVuZ3RoKGludGVyc2VjdCh1bmxpc3Qoc3Ryc3BsaXQoZmlzaFtbc3BlY2lmaWNdXVtbIklOVEVSU0VDVCJdXVtpXSwgc3BsaXQgPSAiLCIpKSwgdW5saXN0KHN0cnNwbGl0KGZpc2hbW3NwZWNpZmljXV1bWyJJTlRFUlNFQ1QiXV1bal0sIHNwbGl0ID0gIiwiKSkpKS8obWlubGlzdCkgICAgICAKICAgICAgcmVzdWx0W2osIGldIDwtIHJlc3VsdFtpLCBqXSAgICAgCiAgICB9CiAgfQogIGxpc3RCUHNwZWNpZmljID0gbGlzdChjKHJvd25hbWVzKHJlc3VsdClbMV0pKQogIGk9MQogIHdoaWxlKGkgPCBsKXsKICAgIGo9aQogICAgd2hpbGUoaiA8IGwpewogICAgICBpZihyZXN1bHRbaSwgal0gPCBwKXsgCiAgICAgICAgaT1qCiAgICAgICAgbGlzdEJQc3BlY2lmaWMgPC0gYyhsaXN0QlBzcGVjaWZpYywgcm93bmFtZXMocmVzdWx0KVtqXSkKICAgICAgICBqPWwKICAgICAgfWVsc2UgewogICAgICAgIGo9aisxCiAgICAgIH0KICAgIH0KICAgIGlmKGxlbmd0aChsaXN0QlBzcGVjaWZpYyk+bi0xKSAKICAgICAgaT1sCiAgfQogIHJldHVybihsaXN0QlBzcGVjaWZpYykKfQpgYGAKCiMjIERpZmZlcmVudGlhbCBleHByZXNzaW9uIGFuYWx5c2lzIHdpdGggbGltbWEtdm9vbQoKIyMjIEZpbHRlcmluZyB0byByZW1vdmUgbG93bHkgZXhwcmVzc2VkIGdlbmVzICsgTm9ybWFsaXphdGlvbiBmb3IgY29tcG9zaXRpb24gYmlhcwoKdXNlIHRoZSAqZWRnZVIvbGltbWEqIHdvcmtmbG93IHRvIGZpbHRlciBvdXQgbG93bHkgZXhwcmVzc2VkIGdlbmVzLiAqVm9vbSogaXMgdXNlZCB0byBub3JtYWxpemUgdGhlIHJhdyBjb3VudHMuIEEgbGluZWFyIG1peGVkIG1vZGVsIGlzIHVzZWQgdG8gZml0IHRoZSBleHByZXNzaW9uIHZhbHVlcy4gRGVmaW5pbmcgdGhlIG1vZGVsIGlzIGRvbmUgd2l0aCB0aGUgbW9kZWwubWF0cml4IGZ1bmN0aW9uIG9mIGVkZ2VSLiBJbiB0aGUgbW9kZWwgYXJlIGluY2x1ZGVkIGZhY3RvcnMgb2YgaW50ZXJlc3QgKGdyb3VwKS4gSWYgYSBiYXRjaC9wYXRpZW50IGVmZmVjdCBpcyBkZXRlY3RlZCwgaXQgY2FuIGJlIGFkZGVkIHRvIHRoZSBtb2RlbCB0byBhY2NvdW50IGZvciBpdHMgZWZmZWN0LgoKYGBge3IgIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcGFnZWQucHJpbnQ9VFJVRSwgZmlnLndpZHRoID0gNCwgZmlnLmhlaWdodCA9IDN9CmQwIDwtIERHRUxpc3QoZGF0Wy0xXSkKZDAgPC0gY2FsY05vcm1GYWN0b3JzKGQwKQpjdXRvZmYgPC0gMgpkcm9wIDwtIHdoaWNoKGFwcGx5KGNwbShkMCksIDEsIG1heCkgPCBjdXRvZmYpCmQgPC0gZDBbLWRyb3AsXQoKbW0gPC0gbW9kZWwubWF0cml4KH4gMCArIGxlc2lvbl90eXBlK2JhdGNoK3NhbXBsZSwgZGF0YT1tZXRhW2NvbG5hbWVzKGQpLF0pCgojIFdpdGhvdXQgZmlsdGVyaW5nIGxvdyBleHByZXNzZWQgZ2VuZXMKeSA8LSB2b29tKGQwWyxyb3duYW1lcyhtZXRhKV0sIG1tLCBwbG90ID0gVCkKCiMgRmlsdGVyaW5nIGxvdyBleHByZXNzZWQgZ2VuZXMKeSA8LSB2b29tKGRbLHJvd25hbWVzKG1ldGEpXSwgbW0sIHBsb3QgPSBUKQoKIyNnZW5lIG5hbWUgcmVmZXJlbmNlKHJlZl9HKQpjb252X0I9QW5ub3RhdGlvbkRiaTo6c2VsZWN0KG9yZy5Icy5lZy5kYixrZXlzPXJvd25hbWVzKHkkRSksa2V5dHlwZT0nRU5TRU1CTCcsY29sdW1ucz1jKCdHRU5FTkFNRScsJ1NZTUJPTCcpKQpyZWZfRz1jb252X0JbIWR1cGxpY2F0ZWQoY29udl9CWywxXSksXQpyb3duYW1lcyhyZWZfRyk9cmVmX0dbLDFdCiMjCmBgYAoKIyMgUENBIHsudGFic2V0fQpQZXJmb3JtIGEgKlBDQSogb24gdGhlIG5vcm1hbGl6ZWQgc2FtcGxlcyBhbmQgaWRlbnRpZnkgbWFpbiBmYWN0b3JzIG9mIHZhcmlhdGlvbi4gCgojIyMgRGF0YSBpbmNsdWRpbmcgYmF0Y2ggZWZmZWN0CmBgYHtyICBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIHBhZ2VkLnByaW50PVRSVUUsIGZpZy53aWR0aCA9IDcsIGZpZy5oZWlnaHQgPSA2fQpCRCA8LSBwY2EoeSRFLCBtZXRhZGF0YSA9IG1ldGEpCmJpcGxvdChCRCwgY29sYnkgPSAnYmF0Y2gnLGhsaW5lID0gMCwgdmxpbmUgPSAwLGxlZ2VuZFBvc2l0aW9uID0gJ3JpZ2h0JywgbGFiPSIiLHRpdGxlID0gIkRhdGEgaW5jbHVkaW5nIGJhdGNoIGVmZmVjdCArIHBhdGllbnQgZWZmZWN0IikKYGBgCgojIyMgT25seSBCYXRjaCBlZmZlY3QgcmVtb3ZlZCBmcm9tIGRhdGEgKGNvbG9yIGJ5IHBhdGllbnQpCmBgYHtyICBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIHBhZ2VkLnByaW50PVRSVUUsIGZpZy53aWR0aCA9IDcsIGZpZy5oZWlnaHQgPSA2fQpCRENvcnJCIDwtIHJlbW92ZUJhdGNoRWZmZWN0KHkkRSxiYXRjaCA9IG1ldGEkYmF0Y2gpCkJEMUIgPC0gcGNhKEJEQ29yckIsIG1ldGFkYXRhID0gbWV0YSkKYmlwbG90KEJEMUIsIGNvbGJ5ID0gJ3NhbXBsZScsc2hhcGUgPSAnc2V4JywgaGxpbmUgPSAwLCB2bGluZSA9IDAsbGVnZW5kUG9zaXRpb24gPSAncmlnaHQnLCBsYWI9IiIsdGl0bGU9Ik9ubHkgQmF0Y2ggZWZmZWN0IHJlbW92ZWQgZnJvbSBkYXRhIikKYGBgCgoKIyMjIE9ubHkgQmF0Y2ggZWZmZWN0IHJlbW92ZWQgZnJvbSBkYXRhIChjb2xvciBieSBiYXRjaCkKYGBge3IgIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcGFnZWQucHJpbnQ9VFJVRSwgZmlnLndpZHRoID0gNywgZmlnLmhlaWdodCA9IDZ9CmJpcGxvdChCRDFCLCBjb2xieSA9ICdiYXRjaCcsaGxpbmUgPSAwLCB2bGluZSA9IDAsbGVnZW5kUG9zaXRpb24gPSAncmlnaHQnLCBsYWI9IiIsdGl0bGU9Ik9ubHkgQmF0Y2ggZWZmZWN0IHJlbW92ZWQgZnJvbSBkYXRhIikKYGBgCgojIyMgUGF0aWVudCtCYXRjaCBlZmZlY3QgcmVtb3ZlZCBmcm9tIGRhdGEgKGNvbG9yIGJ5IHNhbXBsZSkKYGBge3IgIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcGFnZWQucHJpbnQ9VFJVRSwgZmlnLndpZHRoID0gNywgZmlnLmhlaWdodCA9IDZ9CkJEQ29yckJTIDwtIHJlbW92ZUJhdGNoRWZmZWN0KHkkRSxiYXRjaCA9IG1ldGEkYmF0Y2gsIGJhdGNoMiA9IG1ldGEkc2FtcGxlKQpCRDFCUyA8LSBwY2EoQkRDb3JyQlMsIG1ldGFkYXRhID0gbWV0YSkKYmlwbG90KEJEMUJTLCBjb2xieSA9ICdzYW1wbGUnLGhsaW5lID0gMCwgdmxpbmUgPSAwLGxlZ2VuZFBvc2l0aW9uID0gJ3JpZ2h0JywgbGFiPSIiLHRpdGxlPSJCYXRjaCtQYXRpZW50IGVmZmVjdCByZW1vdmVkIGZyb20gZGF0YSIpCmBgYAoKIyMjIFBhdGllbnQrQmF0Y2ggZWZmZWN0IHJlbW92ZWQgZnJvbSBkYXRhIChjb2xvciBieSBsZXNpb25fdHlwZSBhbmQgc2V4KQpgYGB7ciAgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBwYWdlZC5wcmludD1UUlVFLCBmaWcud2lkdGggPSA3LCBmaWcuaGVpZ2h0ID0gNn0KYmlwbG90KEJEMUJTLCBjb2xieSA9ICdsZXNpb25fdHlwZScsc2hhcGUgPSAnc2V4JyxobGluZSA9IDAsIHZsaW5lID0gMCxsZWdlbmRQb3NpdGlvbiA9ICdyaWdodCcsIGxhYj0iIix0aXRsZT0iQmF0Y2grUGF0aWVudCBlZmZlY3QgcmVtb3ZlZCBmcm9tIGRhdGEiKQpgYGAKCgojIyAgU3BlY2lmeSBDb250cmFzdChzKSBvZiBpbnRlcmVzdAoKVXNlIGEgbGluZWFyIG1vZGVsIHRvIGZpdCB2b29tZWQgY291bnRzIChsb2dDUE0pLiBJbnN0YW5jaWF0ZSB0aGUgY29tcGFyaXNvbnMgb2YgaW50ZXJlc3QgYnkgdXNpbmcgdGhlIGNvbnRyYXN0IGFwcHJvYWNoIGZyb20gKmxpbW1hKi4gRXh0cmFjdCB0aGUgcmVzdWx0cywgYW5ub3RhdGUgdGhlIHRhYmxlcyBhbmQgbWVyZ2UgdGhlbSBpbnRvIGEgZ2xvYmFsIHJlc3VsdCBkYXRhZnJhbWUuIAoKYGBge3IgIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcGFnZWQucHJpbnQ9VFJVRX0KZml0IDwtIGxtRml0KHksIG1tKQpjb250ciA8LSBtYWtlQ29udHJhc3RzKAogIEEgPSBsZXNpb25fdHlwZVdNTCAtIGxlc2lvbl90eXBlTkFXTSwKICBCID0gbGVzaW9uX3R5cGVXTUwgLSBsZXNpb25fdHlwZUNMLAogIEMgPSBsZXNpb25fdHlwZUNMIC0gbGVzaW9uX3R5cGVOQUdNLAogIEQgPSBsZXNpb25fdHlwZU5BV00gLSBsZXNpb25fdHlwZU5BR00sCiAgRSA9IGxlc2lvbl90eXBlUFZNTCAtIGxlc2lvbl90eXBlTkFXTSwKICBGID0gbGVzaW9uX3R5cGVQVk1MIC0gbGVzaW9uX3R5cGVXTUwsCiAgRyA9IGxlc2lvbl90eXBlUFZNTCAtIGxlc2lvbl90eXBlQ0wsCiAgbGV2ZWxzID0gY29sbmFtZXMoY29lZihmaXQpKSkKdG1wIDwtIGNvbnRyYXN0cy5maXQoZml0LCBjb250cikKdG1wIDwtIGVCYXllcyh0bXApCgpyZXNBIDwtIHRvcFRhYmxlKHRtcCwgc29ydC5ieSA9ICJQIiwgbiA9IEluZixjb2VmPSdBJykKcmVzQiA8LSB0b3BUYWJsZSh0bXAsIHNvcnQuYnkgPSAiUCIsIG4gPSBJbmYsY29lZj0nQicpCnJlc0MgPC0gdG9wVGFibGUodG1wLCBzb3J0LmJ5ID0gIlAiLCBuID0gSW5mLGNvZWY9J0MnKQpyZXNEIDwtIHRvcFRhYmxlKHRtcCwgc29ydC5ieSA9ICJQIiwgbiA9IEluZixjb2VmPSdEJykKcmVzRSA8LSB0b3BUYWJsZSh0bXAsIHNvcnQuYnkgPSAiUCIsIG4gPSBJbmYsY29lZj0nRScpCnJlc0YgPC0gdG9wVGFibGUodG1wLCBzb3J0LmJ5ID0gIlAiLCBuID0gSW5mLGNvZWY9J0YnKQpyZXNHIDwtIHRvcFRhYmxlKHRtcCwgc29ydC5ieSA9ICJQIiwgbiA9IEluZixjb2VmPSdHJykKYGBgCgoKIyMgQ29tcGFyaXNvbnMgYmV0d2VlbiBjb25kaXRpb25zIChWb2xjYW5vIHBsb3QpIHsudGFic2V0fQoKUGxvdCByZXN1bHRzIGluIHRoZSBmb3JtIG9mIHZvbGNhbm8gcGxvdHMuIFRocmVzaG9sZHMgdXNlZCBhcmUgYWRqLlAuVmFsPDAuMDUgJiB8bG9nRkN8PjEuIFJlZCBnZW5lcyBhcmUgdXByZWd1bGF0ZWQgaW4gdGhlIGZpcnN0IGdyb3VwIGFzIGZvdW5kIGluIHRoZSBzdWJ0aXRsZSBvZiBlYWNoIGdyYXBoLiAKCiMjIyBQVk1MX3ZzX05BV00KYGBge3IgIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcGFnZWQucHJpbnQ9VFJVRSwgZmlnLndpZHRoID0gNCwgZmlnLmhlaWdodCA9IDN9CnJlc0UkZ2VuZV9pZCA9ICByb3duYW1lcyhyZXNFKQpyZXNFJGNvbXAgPSAnUFZNTF92c19OQVdNJwpyZXNFJGdlbmVfbmFtZSA9IHJlZl9HW3Jvd25hbWVzKHJlc0UpLDNdCnJlc0U9cmVzRVtvcmRlcigtYWJzKHJlc0UkbG9nRkMpKSxdCnJlc0Ukc2hvdyA9IEYKcmVzRVsxOjE1LCdzaG93J109VApyZXNFJHNpZ24gPSAnTlMnCnJlc0Vbd2hpY2gocmVzRSRhZGouUC5WYWw8MC4wNSZyZXNFJGxvZ0ZDPjEpLCdzaWduJ109J1VQJwpyZXNFW3doaWNoKHJlc0UkYWRqLlAuVmFsPDAuMDUmcmVzRSRsb2dGQzwoLTEpKSwnc2lnbiddPSdETicKZ2dwbG90KHJlc0UsYWVzKGxvZ0ZDLC1sb2cxMChQLlZhbHVlKSxjb2w9c2lnbikpK2dlb21fcG9pbnRfaW50ZXJhY3RpdmUoYWVzKHg9bG9nRkMseT0tbG9nMTAoUC5WYWx1ZSksY29sb3I9c2lnbix0b29sdGlwID0gZ2VuZV9uYW1lLGRhdGFfaWQgPSBnZW5lX25hbWUpKSt0aGVtZV9idygpK3NjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9c2lnbl9jb2xzKSsgZ2VvbV9sYWJlbF9yZXBlbChkYXRhPXN1YnNldChyZXNFLHNob3c9PVQpLGFlcyhsYWJlbD1nZW5lX25hbWUpLGNvbD0nYmxhY2snLHNpemU9Myxmb3JjZT0zMCxmaWxsID0gYWxwaGEoYygid2hpdGUiKSwwLjUpKStnZ3RpdGxlKCdQVk1MX3ZzX05BV00nKQpgYGAKCiMjIyBXTUxfdnNfTkFXTQpgYGB7ciAgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBwYWdlZC5wcmludD1UUlVFLCBmaWcud2lkdGggPSA0LCBmaWcuaGVpZ2h0ID0gM30KcmVzQSRnZW5lX2lkID0gIHJvd25hbWVzKHJlc0EpCnJlc0EkY29tcCA9ICdXTUxfdnNfTkFXTScKcmVzQSRnZW5lX25hbWUgPSByZWZfR1tyb3duYW1lcyhyZXNBKSwzXQpyZXNBPXJlc0Fbb3JkZXIoLWFicyhyZXNBJGxvZ0ZDKSksXQpyZXNBJHNob3cgPSBGCnJlc0FbMToxNSwnc2hvdyddPVQKcmVzQSRzaWduID0gJ05TJwpyZXNBW3doaWNoKHJlc0EkYWRqLlAuVmFsPDAuMDUmcmVzQSRsb2dGQz4xKSwnc2lnbiddPSdVUCcKcmVzQVt3aGljaChyZXNBJGFkai5QLlZhbDwwLjA1JnJlc0EkbG9nRkM8KC0xKSksJ3NpZ24nXT0nRE4nCmdncGxvdChyZXNBLGFlcyhsb2dGQywtbG9nMTAoUC5WYWx1ZSksY29sPXNpZ24pKStnZW9tX3BvaW50X2ludGVyYWN0aXZlKGFlcyh4PWxvZ0ZDLHk9LWxvZzEwKFAuVmFsdWUpLGNvbG9yPXNpZ24sdG9vbHRpcCA9IGdlbmVfbmFtZSxkYXRhX2lkID0gZ2VuZV9uYW1lKSkrdGhlbWVfYncoKStzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPXNpZ25fY29scykrIGdlb21fbGFiZWxfcmVwZWwoZGF0YT1zdWJzZXQocmVzQSxzaG93PT1UKSxhZXMobGFiZWw9Z2VuZV9uYW1lKSxjb2w9J2JsYWNrJyxzaXplPTMsZm9yY2U9MzAsZmlsbCA9IGFscGhhKGMoIndoaXRlIiksMC41KSkrZ2d0aXRsZSgnV01MX3ZzX05BV00nKQpgYGAKCiMjIyBXTUxfdnNfQ0wKYGBge3IgIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcGFnZWQucHJpbnQ9VFJVRSwgZmlnLndpZHRoID0gNCwgZmlnLmhlaWdodCA9IDN9CnJlc0IkZ2VuZV9pZCA9ICByb3duYW1lcyhyZXNCKQpyZXNCJGNvbXAgPSAnV01MX3ZzX0NMJwpyZXNCJGdlbmVfbmFtZSA9IHJlZl9HW3Jvd25hbWVzKHJlc0IpLDNdCnJlc0I9cmVzQltvcmRlcigtYWJzKHJlc0IkbG9nRkMpKSxdCnJlc0Ikc2hvdyA9IEYKcmVzQlsxOjE1LCdzaG93J109VApyZXNCJHNpZ24gPSAnTlMnCnJlc0Jbd2hpY2gocmVzQiRhZGouUC5WYWw8MC4wNSZyZXNCJGxvZ0ZDPjEpLCdzaWduJ109J1VQJwpyZXNCW3doaWNoKHJlc0IkYWRqLlAuVmFsPDAuMDUmcmVzQiRsb2dGQzwoLTEpKSwnc2lnbiddPSdETicKZ2dwbG90KHJlc0IsYWVzKGxvZ0ZDLC1sb2cxMChQLlZhbHVlKSxjb2w9c2lnbikpK2dlb21fcG9pbnRfaW50ZXJhY3RpdmUoYWVzKHg9bG9nRkMseT0tbG9nMTAoUC5WYWx1ZSksY29sb3I9c2lnbix0b29sdGlwID0gZ2VuZV9uYW1lLGRhdGFfaWQgPSBnZW5lX25hbWUpKSt0aGVtZV9idygpK3NjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9c2lnbl9jb2xzKSsgZ2VvbV9sYWJlbF9yZXBlbChkYXRhPXN1YnNldChyZXNCLHNob3c9PVQpLGFlcyhsYWJlbD1nZW5lX25hbWUpLGNvbD0nYmxhY2snLHNpemU9Myxmb3JjZT0zMCxmaWxsID0gYWxwaGEoYygid2hpdGUiKSwwLjUpKStnZ3RpdGxlKCdXTUxfdnNfQ0wnKQpgYGAKCiMjIyBDTF92c19OQUdNCmBgYHtyICBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIHBhZ2VkLnByaW50PVRSVUUsIGZpZy53aWR0aCA9IDQsIGZpZy5oZWlnaHQgPSAzfQpyZXNDJGdlbmVfaWQgPSAgcm93bmFtZXMocmVzQykKcmVzQyRjb21wID0gJ0NMX3ZzX05BR00nCnJlc0MkZ2VuZV9uYW1lID0gcmVmX0dbcm93bmFtZXMocmVzQyksM10KcmVzQz1yZXNDW29yZGVyKC1hYnMocmVzQyRsb2dGQykpLF0KcmVzQyRzaG93ID0gRgpyZXNDWzE6MTUsJ3Nob3cnXT1UCnJlc0Mkc2lnbiA9ICdOUycKcmVzQ1t3aGljaChyZXNDJGFkai5QLlZhbDwwLjA1JnJlc0MkbG9nRkM+MSksJ3NpZ24nXT0nVVAnCnJlc0Nbd2hpY2gocmVzQyRhZGouUC5WYWw8MC4wNSZyZXNDJGxvZ0ZDPCgtMSkpLCdzaWduJ109J0ROJwpnZ3Bsb3QocmVzQyxhZXMobG9nRkMsLWxvZzEwKFAuVmFsdWUpLGNvbD1zaWduKSkrZ2VvbV9wb2ludF9pbnRlcmFjdGl2ZShhZXMoeD1sb2dGQyx5PS1sb2cxMChQLlZhbHVlKSxjb2xvcj1zaWduLHRvb2x0aXAgPSBnZW5lX25hbWUsZGF0YV9pZCA9IGdlbmVfbmFtZSkpK3RoZW1lX2J3KCkrc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1zaWduX2NvbHMpKyBnZW9tX2xhYmVsX3JlcGVsKGRhdGE9c3Vic2V0KHJlc0Msc2hvdz09VCksYWVzKGxhYmVsPWdlbmVfbmFtZSksY29sPSdibGFjaycsc2l6ZT0zLGZvcmNlPTMwLGZpbGwgPSBhbHBoYShjKCJ3aGl0ZSIpLDAuNSkpK2dndGl0bGUoJ0NMX3ZzX05BR00nKQpgYGAKCiMjIyBOQVdNX3ZzX05BR00KYGBge3IgIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcGFnZWQucHJpbnQ9VFJVRSwgZmlnLndpZHRoID0gNCwgZmlnLmhlaWdodCA9IDN9CnJlc0QkZ2VuZV9pZCA9ICByb3duYW1lcyhyZXNEKQpyZXNEJGNvbXAgPSAnTkFXTV92c19OQUdNJwpyZXNEJGdlbmVfbmFtZSA9IHJlZl9HW3Jvd25hbWVzKHJlc0QpLDNdCnJlc0Q9cmVzRFtvcmRlcigtYWJzKHJlc0QkbG9nRkMpKSxdCnJlc0Qkc2hvdyA9IEYKcmVzRFsxOjE1LCdzaG93J109VApyZXNEJHNpZ24gPSAnTlMnCnJlc0Rbd2hpY2gocmVzRCRhZGouUC5WYWw8MC4wNSZyZXNEJGxvZ0ZDPjEpLCdzaWduJ109J1VQJwpyZXNEW3doaWNoKHJlc0QkYWRqLlAuVmFsPDAuMDUmcmVzRCRsb2dGQzwoLTEpKSwnc2lnbiddPSdETicKZ2dwbG90KHJlc0QsYWVzKGxvZ0ZDLC1sb2cxMChQLlZhbHVlKSxjb2w9c2lnbikpK2dlb21fcG9pbnRfaW50ZXJhY3RpdmUoYWVzKHg9bG9nRkMseT0tbG9nMTAoUC5WYWx1ZSksY29sb3I9c2lnbix0b29sdGlwID0gZ2VuZV9uYW1lLGRhdGFfaWQgPSBnZW5lX25hbWUpKSt0aGVtZV9idygpK3NjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9c2lnbl9jb2xzKSsgZ2VvbV9sYWJlbF9yZXBlbChkYXRhPXN1YnNldChyZXNELHNob3c9PVQpLGFlcyhsYWJlbD1nZW5lX25hbWUpLGNvbD0nYmxhY2snLHNpemU9Myxmb3JjZT0zMCxmaWxsID0gYWxwaGEoYygid2hpdGUiKSwwLjUpKStnZ3RpdGxlKCdOQVdNX3ZzX05BR00nKQpgYGAKCiMjIyBQVk1MX3ZzX1dNTApgYGB7ciAgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBwYWdlZC5wcmludD1UUlVFLCBmaWcud2lkdGggPSA0LCBmaWcuaGVpZ2h0ID0gM30KcmVzRiRnZW5lX2lkID0gIHJvd25hbWVzKHJlc0YpCnJlc0YkY29tcCA9ICdQVk1MX3ZzX1dNTCcKcmVzRiRnZW5lX25hbWUgPSByZWZfR1tyb3duYW1lcyhyZXNGKSwzXQpyZXNGPXJlc0Zbb3JkZXIoLWFicyhyZXNGJGxvZ0ZDKSksXQpyZXNGJHNob3cgPSBGCnJlc0ZbMToxNSwnc2hvdyddPVQKcmVzRiRzaWduID0gJ05TJwpyZXNGW3doaWNoKHJlc0YkYWRqLlAuVmFsPDAuMDUmcmVzRiRsb2dGQz4xKSwnc2lnbiddPSdVUCcKcmVzRlt3aGljaChyZXNGJGFkai5QLlZhbDwwLjA1JnJlc0YkbG9nRkM8KC0xKSksJ3NpZ24nXT0nRE4nCmdncGxvdChyZXNGLGFlcyhsb2dGQywtbG9nMTAoUC5WYWx1ZSksY29sPXNpZ24pKStnZW9tX3BvaW50X2ludGVyYWN0aXZlKGFlcyh4PWxvZ0ZDLHk9LWxvZzEwKFAuVmFsdWUpLGNvbG9yPXNpZ24sdG9vbHRpcCA9IGdlbmVfbmFtZSxkYXRhX2lkID0gZ2VuZV9uYW1lKSkrdGhlbWVfYncoKStzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPXNpZ25fY29scykrIGdlb21fbGFiZWxfcmVwZWwoZGF0YT1zdWJzZXQocmVzRixzaG93PT1UKSxhZXMobGFiZWw9Z2VuZV9uYW1lKSxjb2w9J2JsYWNrJyxzaXplPTMsZm9yY2U9MzAsZmlsbCA9IGFscGhhKGMoIndoaXRlIiksMC41KSkrZ2d0aXRsZSgnUFZNTF92c19XTUwnKQpgYGAKCiMjIyBQVk1MX3ZzX0NMCmBgYHtyICBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIHBhZ2VkLnByaW50PVRSVUUsIGZpZy53aWR0aCA9IDQsIGZpZy5oZWlnaHQgPSAzfQpyZXNHJGdlbmVfaWQgPSAgcm93bmFtZXMocmVzRykKcmVzRyRjb21wID0gJ1BWTUxfdnNfQ0wnCnJlc0ckZ2VuZV9uYW1lID0gcmVmX0dbcm93bmFtZXMocmVzRyksM10KcmVzRz1yZXNHW29yZGVyKC1hYnMocmVzRyRsb2dGQykpLF0KcmVzRyRzaG93ID0gRgpyZXNHWzE6MTUsJ3Nob3cnXT1UCnJlc0ckc2lnbiA9ICdOUycKcmVzR1t3aGljaChyZXNHJGFkai5QLlZhbDwwLjA1JnJlc0ckbG9nRkM+MSksJ3NpZ24nXT0nVVAnCnJlc0dbd2hpY2gocmVzRyRhZGouUC5WYWw8MC4wNSZyZXNHJGxvZ0ZDPCgtMSkpLCdzaWduJ109J0ROJwpnZ3Bsb3QocmVzRyxhZXMobG9nRkMsLWxvZzEwKFAuVmFsdWUpLGNvbD1zaWduKSkrZ2VvbV9wb2ludF9pbnRlcmFjdGl2ZShhZXMoeD1sb2dGQyx5PS1sb2cxMChQLlZhbHVlKSxjb2xvcj1zaWduLHRvb2x0aXAgPSBnZW5lX25hbWUsZGF0YV9pZCA9IGdlbmVfbmFtZSkpK3RoZW1lX2J3KCkrc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1zaWduX2NvbHMpKyBnZW9tX2xhYmVsX3JlcGVsKGRhdGE9c3Vic2V0KHJlc0csc2hvdz09VCksYWVzKGxhYmVsPWdlbmVfbmFtZSksY29sPSdibGFjaycsc2l6ZT0zLGZvcmNlPTMwLGZpbGwgPSBhbHBoYShjKCJ3aGl0ZSIpLDAuNSkpK2dndGl0bGUoJ1BWTUxfdnNfQ0wnKQpgYGAKCkJveHBsb3RzIG9mIHNlbGVjdCBnZW5lcyBkZW1vbnN0cmF0aW5nIHNpZ25pZmljYW50IGRpZmZlcmVudGlhbCBnZW5lIGV4cHJlc3Npb24uCgpgYGB7ciwgZmlnLndpZHRoID0gOCwgZmlnLmhlaWdodCA9IDd9CkNJQkFSMiA8LSBwbG90LmdlbmUoIkNJQkFSMiIpCkROQUg1IDwtIHBsb3QuZ2VuZSgiRE5BSDUiKQppcmYxIDwtIHBsb3QuZ2VuZSgiSVJGMSIpCkxSUklRMSA8LSBwbG90LmdlbmUoIkxSUklRMSIpCmljYW0xIDwtIHBsb3QuZ2VuZSgiSUNBTTEiKQpPREFEMiA8LSBwbG90LmdlbmUoIk9EQUQyIikKdmNhbTEgPC0gcGxvdC5nZW5lKCJWQ0FNMSIpCkNEMjQgPC0gcGxvdC5nZW5lKCJDRDI0IikKZGxlYzEgPC0gcGxvdC5nZW5lKCJETEVDMSIpCmNmYXA1NCA8LSBwbG90LmdlbmUoIkNGQVA1NCIpCmZoYWQxIDwtIHBsb3QuZ2VuZSgiRkhBRDEiKQpkeW5sdDUgPC0gcGxvdC5nZW5lKCJEWU5MVDUiKQpjZmFwNDMgPC0gcGxvdC5nZW5lKCJDRkFQNDMiKQpyc3BoMSA8LSBwbG90LmdlbmUoIlJTUEgxIikKZG5haTMgPC0gcGxvdC5nZW5lKCJETkFJMyIpCmN4Y2wxNCA8LSBwbG90LmdlbmUoIkNYQ0wxNCIpCmdnYXJyYW5nZShDSUJBUjIsIEROQUg1LCBMUlJJUTEsIE9EQUQyLCBpcmYxLCBDRDI0LCBpY2FtMSwgZGxlYzEsIGNmYXA1NCwgdmNhbTEsIGZoYWQxLCBkeW5sdDUsIGNmYXA0MywgcnNwaDEsIGRuYWkzLCBjeGNsMTQsIG5jb2wgPSA0LCBucm93ID0gNCxhbGlnbiA9IGMoImh2IiksIGNvbW1vbi5sZWdlbmQgPSBUUlVFLCBsZWdlbmQ9ImJvdHRvbSIpCmBgYAoKQ29tcGFyZSBmb2xkLWNoYW5nZXMgYWNyb3NzIGNvbmRpdGlvbnMuCgpgYGB7ciBvdXQud2lkdGg9IjMwMCUiLG1lc3NhZ2U9RixmaWcud2lkdGg9NCwgb3V0LndpZHRoPSIzMCUiLCBmaWcuYWxpZ249ImRlZmF1bHQifQpkZiA9IGRhdGEuZnJhbWUoY2JpbmQocmVzRSRsb2dGQyxyZXNBW3Jvd25hbWVzKHJlc0UpLCdsb2dGQyddLHJlc0Jbcm93bmFtZXMocmVzRSksJ2xvZ0ZDJ10scmVzRltyb3duYW1lcyhyZXNFKSwnbG9nRkMnXSkpCmNvbG5hbWVzKGRmKT1jKCdXTUxfdnNfTkFXTScsJ1BWTUxfdnNfTkFXTScsJ1dNTF92c19DTCcsJ1BWTUxfdnNfV01MJykKCnAxPWdncGxvdChkZixhZXMoV01MX3ZzX05BV00sUFZNTF92c19OQVdNKSkrZ2VvbV9wb2ludCgpK3RoZW1lX2J3KCkrc3RhdF9jb3IoKStnZW9tX3Ntb290aChtZXRob2Q9J2xtJykrZ2d0aXRsZSgnRm9sZC1DaGFuZ2VzIENvcnJlbGF0aW9uJykKcDI9Z2dwbG90KGRmLGFlcyhXTUxfdnNfTkFXTSxXTUxfdnNfQ0wpKStnZW9tX3BvaW50KCkrdGhlbWVfYncoKStzdGF0X2NvcigpK2dlb21fc21vb3RoKG1ldGhvZD0nbG0nKStnZ3RpdGxlKCdGb2xkLUNoYW5nZXMgQ29ycmVsYXRpb24nKQpwMz1nZ3Bsb3QoZGYsYWVzKFdNTF92c19OQVdNLFBWTUxfdnNfV01MKSkrZ2VvbV9wb2ludCgpK3RoZW1lX2J3KCkrc3RhdF9jb3IoKStnZW9tX3Ntb290aChtZXRob2Q9J2xtJykrZ2d0aXRsZSgnRm9sZC1DaGFuZ2VzIENvcnJlbGF0aW9uJykKcDQ9Z2dwbG90KGRmLGFlcyhQVk1MX3ZzX05BV00sV01MX3ZzX0NMKSkrZ2VvbV9wb2ludCgpK3RoZW1lX2J3KCkrc3RhdF9jb3IoKStnZW9tX3Ntb290aChtZXRob2Q9J2xtJykrZ2d0aXRsZSgnRm9sZC1DaGFuZ2VzIENvcnJlbGF0aW9uJykKcDU9Z2dwbG90KGRmLGFlcyhQVk1MX3ZzX05BV00sUFZNTF92c19XTUwpKStnZW9tX3BvaW50KCkrdGhlbWVfYncoKStzdGF0X2NvcigpK2dlb21fc21vb3RoKG1ldGhvZD0nbG0nKStnZ3RpdGxlKCdGb2xkLUNoYW5nZXMgQ29ycmVsYXRpb24nKQpwNj1nZ3Bsb3QoZGYsYWVzKFdNTF92c19DTCxQVk1MX3ZzX1dNTCkpK2dlb21fcG9pbnQoKSt0aGVtZV9idygpK3N0YXRfY29yKCkrZ2VvbV9zbW9vdGgobWV0aG9kPSdsbScpK2dndGl0bGUoJ0ZvbGQtQ2hhbmdlcyBDb3JyZWxhdGlvbicpCgpwMQpwMgpwMwpwNApwNQpwNgoKYGBgCgoKCiMjIEdlbmUgb250b2xvZ3kgdGVybSBlbnJpY2htZW50IGFuYWx5c2lzIG9mIGNvbXBhcmlzb25zIGJldHdlZW4gY29uZGl0aW9ucyAgey50YWJzZXR9CgpUaGlzIGV4dHJhY3RzIGJpb2xvZ2ljYWwgc2lnbmF0dXJlcyBmcm9tIHRoZSB0cmFuc2NyaXB0b21pYyBjaGFuZ2VzIGZvdW5kIGluIHRoZSBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBhbmFseXNpcwoKYGBge3IgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBwYWdlZC5wcmludD1UUlVFfQplbnIuYT1maW5kX2VucmljaG1lbnRzKHJlc0EpCmVuci5iPWZpbmRfZW5yaWNobWVudHMocmVzQikKZW5yLmM9ZmluZF9lbnJpY2htZW50cyhyZXNDKQplbnIuZD1maW5kX2VucmljaG1lbnRzKHJlc0QpCmVuci5lPWZpbmRfZW5yaWNobWVudHMocmVzRSkKZW5yLmY9ZmluZF9lbnJpY2htZW50cyhyZXNGKQplbnIuZz1maW5kX2VucmljaG1lbnRzKHJlc0cpCmBgYAoKCiMjIyBCaW9sb2dpY2FsIFByb2Nlc3NlcwpgYGB7ciBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIHBhZ2VkLnByaW50PVRSVUUsIGZpZy53aWR0aCA9MTAsIGZpZy5oZWlnaHQgPSA5fQplbnJBID0gZW5yLmEkZW5yJGJwCmVuckE9ZW5yQVtvcmRlcihlbnJBJHBhZGopLF0KZW5yQSRjb21wID0gdW5pcXVlKHJlc0EkY29tcCkKCmVuckIgPSBlbnIuYiRlbnIkYnAKZW5yQj1lbnJCW29yZGVyKGVuckIkcGFkaiksXQplbnJCJGNvbXAgPSB1bmlxdWUocmVzQiRjb21wKQoKZW5yQyA9IGVuci5jJGVuciRicAplbnJDPWVuckNbb3JkZXIoZW5yQyRwYWRqKSxdCmVuckMkY29tcCA9IHVuaXF1ZShyZXNDJGNvbXApCgplbnJEID0gZW5yLmQkZW5yJGJwCmVuckQ9ZW5yRFtvcmRlcihlbnJEJHBhZGopLF0KZW5yRCRjb21wID0gdW5pcXVlKHJlc0QkY29tcCkKCmVuckUgPSBlbnIuZSRlbnIkYnAKZW5yRT1lbnJFW29yZGVyKGVuckUkcGFkaiksXQplbnJFJGNvbXAgPSB1bmlxdWUocmVzRSRjb21wKQoKZW5yRiA9IGVuci5mJGVuciRicAplbnJGPWVuckZbb3JkZXIoZW5yRiRwYWRqKSxdCmVuckYkY29tcCA9IHVuaXF1ZShyZXNGJGNvbXApCgplbnJHID0gZW5yLmckZW5yJGJwCmVuckc9ZW5yR1tvcmRlcihlbnJHJHBhZGopLF0KZW5yRyRjb21wID0gdW5pcXVlKHJlc0ckY29tcCkKCnBhdGhzID0gYyhoZWFkKGVuckEsMTApJHBhdGh3YXksCiAgICAgICAgICBoZWFkKGVuckIsMTApJHBhdGh3YXksCiAgICAgICAgICBoZWFkKGVuckMsMTApJHBhdGh3YXksCiAgICAgICAgICBoZWFkKGVuckQsMTApJHBhdGh3YXksCiAgICAgICAgICBoZWFkKGVuckUsMTApJHBhdGh3YXksCiAgICAgICAgICBoZWFkKGVuckYsMTApJHBhdGh3YXksCiAgICAgICAgICBoZWFkKGVuckcsMTApJHBhdGh3YXkgKQoKcGF0aHM9dW5pcXVlKHBhdGhzKQpyYj1yYmluZChlbnJBW3doaWNoKGVuckEkcGF0aHdheSVpbiVwYXRocyksYygncHZhbCcsJ2xlYWRpbmdFZGdlJywnTkVTJywnY29tcCcsJ3BhdGh3YXknKV0sCiAgICAgICAgIGVuckJbd2hpY2goZW5yQiRwYXRod2F5JWluJXBhdGhzKSxjKCdwdmFsJywnbGVhZGluZ0VkZ2UnLCdORVMnLCdjb21wJywncGF0aHdheScpXSwKICAgICAgICAgZW5yQ1t3aGljaChlbnJDJHBhdGh3YXklaW4lcGF0aHMpLGMoJ3B2YWwnLCdsZWFkaW5nRWRnZScsJ05FUycsJ2NvbXAnLCdwYXRod2F5JyldLAogICAgICAgICBlbnJEW3doaWNoKGVuckQkcGF0aHdheSVpbiVwYXRocyksYygncHZhbCcsJ2xlYWRpbmdFZGdlJywnTkVTJywnY29tcCcsJ3BhdGh3YXknKV0sCiAgICAgICAgIGVuckVbd2hpY2goZW5yRSRwYXRod2F5JWluJXBhdGhzKSxjKCdwdmFsJywnbGVhZGluZ0VkZ2UnLCdORVMnLCdjb21wJywncGF0aHdheScpXSwKICAgICAgICAgZW5yRlsgd2hpY2goZW5yRiRwYXRod2F5JWluJXBhdGhzKSxjKCdwdmFsJywnbGVhZGluZ0VkZ2UnLCdORVMnLCdjb21wJywncGF0aHdheScpXSwKICAgICAgICAgZW5yR1t3aGljaChlbnJHJHBhdGh3YXklaW4lcGF0aHMpLGMoJ3B2YWwnLCdsZWFkaW5nRWRnZScsJ05FUycsJ2NvbXAnLCdwYXRod2F5JyldKQpyYlt3aGljaChyYiRwYWRqPj0wLjEpLCdORVMnXT1OQQpyYiRwYXRod2F5IDwtIGdzdWIoIkdPQlAiLCAiIixyYiRwYXRod2F5KQpyYiRwYXRod2F5IDwtIGdzdWIoIl8iLCAiICIscmIkcGF0aHdheSkKc3MgID0gc3Ryc3BsaXQoYXMuY2hhcmFjdGVyKHJiJGxlYWRpbmdFZGdlKSwnLCcpCnJiJG5fZ2VuZXMgPSB1bmxpc3QobGFwcGx5KHNzLGxlbmd0aCkpCnJiJHB2YWwgPC0gYXMubnVtZXJpYyhyYiRwdmFsKQpyYlt3aGljaChyYiRwdmFsPj0wLjEpLCdwdmFsJ109TkEKZ2dwbG90KG5hLm9taXQocmIpLGFlcyhwYXRod2F5LGNvbXAsZmlsbD1ORVMpKStnZW9tX3BvaW50KGFlcyhzaXplPXB2YWwpLHNoYXBlPTIxKStzY2FsZV94X2Rpc2NyZXRlKGxhYmVsID0gZnVuY3Rpb24oeCkgc3RyaW5ncjo6c3RyX3RydW5jKHgsNTApKSt0aGVtZV9idygpK2Nvb3JkX2ZsaXAoKSt0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoIGFuZ2xlPTYwLGhqdXN0PTEpKStzY2FsZV9maWxsX2dyYWRpZW50bihjb2xvcnM9cmV2KGJyZXdlci5wYWwoMTEsJ1JkWWxCdScpKSkrIHNjYWxlX3NpemUodHJhbnMgPSAncmV2ZXJzZScpKyB0aGVtZShheGlzLnRleHQgPSBlbGVtZW50X3RleHQoZmFjZT0iYm9sZCIpKQpgYGAKCiMjIyBNb2xlY3VsYXIgRnVuY3Rpb24KYGBge3IgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBwYWdlZC5wcmludD1UUlVFLCBmaWcud2lkdGggPSAxMCwgZmlnLmhlaWdodCA9IDl9CmVuckEgPSBlbnIuYSRlbnIkbWYKZW5yQT1lbnJBW29yZGVyKGVuckEkcGFkaiksXQplbnJBJGNvbXAgPSB1bmlxdWUocmVzQSRjb21wKQoKZW5yQiA9IGVuci5iJGVuciRtZgplbnJCPWVuckJbb3JkZXIoZW5yQiRwYWRqKSxdCmVuckIkY29tcCA9IHVuaXF1ZShyZXNCJGNvbXApCgplbnJDID0gZW5yLmMkZW5yJG1mCmVuckM9ZW5yQ1tvcmRlcihlbnJDJHBhZGopLF0KZW5yQyRjb21wID0gdW5pcXVlKHJlc0MkY29tcCkKCmVuckQgPSBlbnIuZCRlbnIkbWYKZW5yRD1lbnJEW29yZGVyKGVuckQkcGFkaiksXQplbnJEJGNvbXAgPSB1bmlxdWUocmVzRCRjb21wKQoKZW5yRSA9IGVuci5lJGVuciRtZgplbnJFPWVuckVbb3JkZXIoZW5yRSRwYWRqKSxdCmVuckUkY29tcCA9IHVuaXF1ZShyZXNFJGNvbXApCgplbnJGID0gZW5yLmYkZW5yJG1mCmVuckY9ZW5yRltvcmRlcihlbnJGJHBhZGopLF0KZW5yRiRjb21wID0gdW5pcXVlKHJlc0YkY29tcCkKCmVuckcgPSBlbnIuZyRlbnIkbWYKZW5yRz1lbnJHW29yZGVyKGVuckckcGFkaiksXQplbnJHJGNvbXAgPSB1bmlxdWUocmVzRyRjb21wKQoKcGF0aHMgPSBjKGhlYWQoZW5yQSwxMCkkcGF0aHdheSwKICAgICAgICAgIGhlYWQoZW5yQiwxMCkkcGF0aHdheSwKICAgICAgICAgIGhlYWQoZW5yQywxMCkkcGF0aHdheSwKICAgICAgICAgIGhlYWQoZW5yRCwxMCkkcGF0aHdheSwKICAgICAgICAgIGhlYWQoZW5yRSwxMCkkcGF0aHdheSwKICAgICAgICAgIGhlYWQoZW5yRiwxMCkkcGF0aHdheSwKICAgICAgICAgIGhlYWQoZW5yRywxMCkkcGF0aHdheSApCgpwYXRocz11bmlxdWUocGF0aHMpCnJiPXJiaW5kKGVuckFbd2hpY2goZW5yQSRwYXRod2F5JWluJXBhdGhzKSxjKCdwdmFsJywnbGVhZGluZ0VkZ2UnLCdORVMnLCdjb21wJywncGF0aHdheScpXSwKICAgICAgICAgZW5yQlt3aGljaChlbnJCJHBhdGh3YXklaW4lcGF0aHMpLGMoJ3B2YWwnLCdsZWFkaW5nRWRnZScsJ05FUycsJ2NvbXAnLCdwYXRod2F5JyldLAogICAgICAgICBlbnJDW3doaWNoKGVuckMkcGF0aHdheSVpbiVwYXRocyksYygncHZhbCcsJ2xlYWRpbmdFZGdlJywnTkVTJywnY29tcCcsJ3BhdGh3YXknKV0sCiAgICAgICAgIGVuckRbd2hpY2goZW5yRCRwYXRod2F5JWluJXBhdGhzKSxjKCdwdmFsJywnbGVhZGluZ0VkZ2UnLCdORVMnLCdjb21wJywncGF0aHdheScpXSwKICAgICAgICAgZW5yRVt3aGljaChlbnJFJHBhdGh3YXklaW4lcGF0aHMpLGMoJ3B2YWwnLCdsZWFkaW5nRWRnZScsJ05FUycsJ2NvbXAnLCdwYXRod2F5JyldLAogICAgICAgICBlbnJGWyB3aGljaChlbnJGJHBhdGh3YXklaW4lcGF0aHMpLGMoJ3B2YWwnLCdsZWFkaW5nRWRnZScsJ05FUycsJ2NvbXAnLCdwYXRod2F5JyldLAogICAgICAgICBlbnJHW3doaWNoKGVuckckcGF0aHdheSVpbiVwYXRocyksYygncHZhbCcsJ2xlYWRpbmdFZGdlJywnTkVTJywnY29tcCcsJ3BhdGh3YXknKV0pCnJiW3doaWNoKHJiJHBhZGo+PTAuMSksJ05FUyddPU5BCnJiJHBhdGh3YXkgPC0gZ3N1YigiR09NRiIsICIiLHJiJHBhdGh3YXkpCnJiJHBhdGh3YXkgPC0gZ3N1YigiXyIsICIgIixyYiRwYXRod2F5KQpzcyAgPSBzdHJzcGxpdChhcy5jaGFyYWN0ZXIocmIkbGVhZGluZ0VkZ2UpLCcsJykKcmIkbl9nZW5lcyA9IHVubGlzdChsYXBwbHkoc3MsbGVuZ3RoKSkKcmIkcHZhbCA8LSBhcy5udW1lcmljKHJiJHB2YWwpCnJiW3doaWNoKHJiJHB2YWw+PTAuMSksJ3B2YWwnXT1OQQpnZ3Bsb3QobmEub21pdChyYiksYWVzKHBhdGh3YXksY29tcCxmaWxsPU5FUykpK2dlb21fcG9pbnQoYWVzKHNpemU9cHZhbCksc2hhcGU9MjEpK3NjYWxlX3hfZGlzY3JldGUobGFiZWwgPSBmdW5jdGlvbih4KSBzdHJpbmdyOjpzdHJfdHJ1bmMoeCw1MCkpK3RoZW1lX2J3KCkrY29vcmRfZmxpcCgpK3RoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dCggYW5nbGU9NjAsaGp1c3Q9MSkpK3NjYWxlX2ZpbGxfZ3JhZGllbnRuKGNvbG9ycz1yZXYoYnJld2VyLnBhbCgxMSwnUmRZbEJ1JykpKSsgc2NhbGVfc2l6ZSh0cmFucyA9ICdyZXZlcnNlJykrIHRoZW1lKGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChmYWNlPSJib2xkIikpCmBgYAoKCiMjIyBUcmFuc2NyaXB0aW9uIGZhY3RvciB0YXJnZXRzCmBgYHtyIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcGFnZWQucHJpbnQ9VFJVRSwgZmlnLndpZHRoID0gMTAsIGZpZy5oZWlnaHQgPSA5fQplbnJBID0gZW5yLmEkZW5yJHRmdAplbnJBPWVuckFbb3JkZXIoZW5yQSRwYWRqKSxdCmVuckEkY29tcCA9IHVuaXF1ZShyZXNBJGNvbXApCgplbnJCID0gZW5yLmIkZW5yJHRmdAplbnJCPWVuckJbb3JkZXIoZW5yQiRwYWRqKSxdCmVuckIkY29tcCA9IHVuaXF1ZShyZXNCJGNvbXApCgplbnJDID0gZW5yLmMkZW5yJHRmdAplbnJDPWVuckNbb3JkZXIoZW5yQyRwYWRqKSxdCmVuckMkY29tcCA9IHVuaXF1ZShyZXNDJGNvbXApCgplbnJEID0gZW5yLmQkZW5yJHRmdAplbnJEPWVuckRbb3JkZXIoZW5yRCRwYWRqKSxdCmVuckQkY29tcCA9IHVuaXF1ZShyZXNEJGNvbXApCgplbnJFID0gZW5yLmUkZW5yJHRmdAplbnJFPWVuckVbb3JkZXIoZW5yRSRwYWRqKSxdCmVuckUkY29tcCA9IHVuaXF1ZShyZXNFJGNvbXApCgplbnJGID0gZW5yLmYkZW5yJHRmdAplbnJGPWVuckZbb3JkZXIoZW5yRiRwYWRqKSxdCmVuckYkY29tcCA9IHVuaXF1ZShyZXNGJGNvbXApCgplbnJHID0gZW5yLmckZW5yJHRmdAplbnJHPWVuckdbb3JkZXIoZW5yRyRwYWRqKSxdCmVuckckY29tcCA9IHVuaXF1ZShyZXNHJGNvbXApCgpwYXRocyA9IGMoaGVhZChlbnJBLDEwKSRwYXRod2F5LAogICAgICAgICAgaGVhZChlbnJCLDEwKSRwYXRod2F5LAogICAgICAgICAgaGVhZChlbnJDLDEwKSRwYXRod2F5LAogICAgICAgICAgaGVhZChlbnJELDEwKSRwYXRod2F5LAogICAgICAgICAgaGVhZChlbnJFLDEwKSRwYXRod2F5LAogICAgICAgICAgaGVhZChlbnJGLDEwKSRwYXRod2F5LAogICAgICAgICAgaGVhZChlbnJHLDEwKSRwYXRod2F5ICkKCnBhdGhzPXVuaXF1ZShwYXRocykKcmI9cmJpbmQoZW5yQVt3aGljaChlbnJBJHBhdGh3YXklaW4lcGF0aHMpLGMoJ3B2YWwnLCdsZWFkaW5nRWRnZScsJ05FUycsJ2NvbXAnLCdwYXRod2F5JyldLAogICAgICAgICBlbnJCW3doaWNoKGVuckIkcGF0aHdheSVpbiVwYXRocyksYygncHZhbCcsJ2xlYWRpbmdFZGdlJywnTkVTJywnY29tcCcsJ3BhdGh3YXknKV0sCiAgICAgICAgIGVuckNbd2hpY2goZW5yQyRwYXRod2F5JWluJXBhdGhzKSxjKCdwdmFsJywnbGVhZGluZ0VkZ2UnLCdORVMnLCdjb21wJywncGF0aHdheScpXSwKICAgICAgICAgZW5yRFt3aGljaChlbnJEJHBhdGh3YXklaW4lcGF0aHMpLGMoJ3B2YWwnLCdsZWFkaW5nRWRnZScsJ05FUycsJ2NvbXAnLCdwYXRod2F5JyldLAogICAgICAgICBlbnJFW3doaWNoKGVuckUkcGF0aHdheSVpbiVwYXRocyksYygncHZhbCcsJ2xlYWRpbmdFZGdlJywnTkVTJywnY29tcCcsJ3BhdGh3YXknKV0sCiAgICAgICAgIGVuckZbIHdoaWNoKGVuckYkcGF0aHdheSVpbiVwYXRocyksYygncHZhbCcsJ2xlYWRpbmdFZGdlJywnTkVTJywnY29tcCcsJ3BhdGh3YXknKV0sCiAgICAgICAgIGVuckdbd2hpY2goZW5yRyRwYXRod2F5JWluJXBhdGhzKSxjKCdwdmFsJywnbGVhZGluZ0VkZ2UnLCdORVMnLCdjb21wJywncGF0aHdheScpXSkKcmJbd2hpY2gocmIkcGFkaj49MC4xKSwnTkVTJ109TkEKcmIkcGF0aHdheSA8LSBnc3ViKCJfIiwgIiAiLHJiJHBhdGh3YXkpCnNzICA9IHN0cnNwbGl0KGFzLmNoYXJhY3RlcihyYiRsZWFkaW5nRWRnZSksJywnKQpyYiRuX2dlbmVzID0gdW5saXN0KGxhcHBseShzcyxsZW5ndGgpKQpyYiRwdmFsIDwtIGFzLm51bWVyaWMocmIkcHZhbCkKcmJbd2hpY2gocmIkcHZhbD49MC4xKSwncHZhbCddPU5BCmdncGxvdChuYS5vbWl0KHJiKSxhZXMocGF0aHdheSxjb21wLGZpbGw9TkVTKSkrZ2VvbV9wb2ludChhZXMoc2l6ZT1wdmFsKSxzaGFwZT0yMSkrc2NhbGVfeF9kaXNjcmV0ZShsYWJlbCA9IGZ1bmN0aW9uKHgpIHN0cmluZ3I6OnN0cl90cnVuYyh4LDUwKSkrdGhlbWVfYncoKStjb29yZF9mbGlwKCkrdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KCBhbmdsZT02MCxoanVzdD0xKSkrc2NhbGVfZmlsbF9ncmFkaWVudG4oY29sb3JzPXJldihicmV3ZXIucGFsKDExLCdSZFlsQnUnKSkpKyBzY2FsZV9zaXplKHRyYW5zID0gJ3JldmVyc2UnKSsgdGhlbWUoYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KGZhY2U9ImJvbGQiKSkKYGBgCgoKIyMjIEtFR0cgcGF0aHdheSBkYXRhYmFzZQpgYGB7ciBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIHBhZ2VkLnByaW50PVRSVUUsIGZpZy53aWR0aCA9IDEwLCBmaWcuaGVpZ2h0ID0gOX0KZW5yQSA9IGVuci5hJGVuciRrZWdnCmVuckE9ZW5yQVtvcmRlcihlbnJBJHBhZGopLF0KZW5yQSRjb21wID0gdW5pcXVlKHJlc0EkY29tcCkKCmVuckIgPSBlbnIuYiRlbnIka2VnZwplbnJCPWVuckJbb3JkZXIoZW5yQiRwYWRqKSxdCmVuckIkY29tcCA9IHVuaXF1ZShyZXNCJGNvbXApCgplbnJDID0gZW5yLmMkZW5yJGtlZ2cKZW5yQz1lbnJDW29yZGVyKGVuckMkcGFkaiksXQplbnJDJGNvbXAgPSB1bmlxdWUocmVzQyRjb21wKQoKZW5yRCA9IGVuci5kJGVuciRrZWdnCmVuckQ9ZW5yRFtvcmRlcihlbnJEJHBhZGopLF0KZW5yRCRjb21wID0gdW5pcXVlKHJlc0QkY29tcCkKCmVuckUgPSBlbnIuZSRlbnIka2VnZwplbnJFPWVuckVbb3JkZXIoZW5yRSRwYWRqKSxdCmVuckUkY29tcCA9IHVuaXF1ZShyZXNFJGNvbXApCgplbnJGID0gZW5yLmYkZW5yJGtlZ2cKZW5yRj1lbnJGW29yZGVyKGVuckYkcGFkaiksXQplbnJGJGNvbXAgPSB1bmlxdWUocmVzRiRjb21wKQoKZW5yRyA9IGVuci5nJGVuciRrZWdnCmVuckc9ZW5yR1tvcmRlcihlbnJHJHBhZGopLF0KZW5yRyRjb21wID0gdW5pcXVlKHJlc0ckY29tcCkKCnBhdGhzID0gYyhoZWFkKGVuckEsMTApJHBhdGh3YXksCiAgICAgICAgICBoZWFkKGVuckIsMTApJHBhdGh3YXksCiAgICAgICAgICBoZWFkKGVuckMsMTApJHBhdGh3YXksCiAgICAgICAgICBoZWFkKGVuckQsMTApJHBhdGh3YXksCiAgICAgICAgICBoZWFkKGVuckUsMTApJHBhdGh3YXksCiAgICAgICAgICBoZWFkKGVuckYsMTApJHBhdGh3YXksCiAgICAgICAgICBoZWFkKGVuckcsMTApJHBhdGh3YXkgKQoKcGF0aHM9dW5pcXVlKHBhdGhzKQpyYj1yYmluZChlbnJBW3doaWNoKGVuckEkcGF0aHdheSVpbiVwYXRocyksYygncHZhbCcsJ2xlYWRpbmdFZGdlJywnTkVTJywnY29tcCcsJ3BhdGh3YXknKV0sCiAgICAgICAgIGVuckJbd2hpY2goZW5yQiRwYXRod2F5JWluJXBhdGhzKSxjKCdwdmFsJywnbGVhZGluZ0VkZ2UnLCdORVMnLCdjb21wJywncGF0aHdheScpXSwKICAgICAgICAgZW5yQ1t3aGljaChlbnJDJHBhdGh3YXklaW4lcGF0aHMpLGMoJ3B2YWwnLCdsZWFkaW5nRWRnZScsJ05FUycsJ2NvbXAnLCdwYXRod2F5JyldLAogICAgICAgICBlbnJEW3doaWNoKGVuckQkcGF0aHdheSVpbiVwYXRocyksYygncHZhbCcsJ2xlYWRpbmdFZGdlJywnTkVTJywnY29tcCcsJ3BhdGh3YXknKV0sCiAgICAgICAgIGVuckVbd2hpY2goZW5yRSRwYXRod2F5JWluJXBhdGhzKSxjKCdwdmFsJywnbGVhZGluZ0VkZ2UnLCdORVMnLCdjb21wJywncGF0aHdheScpXSwKICAgICAgICAgZW5yRlsgd2hpY2goZW5yRiRwYXRod2F5JWluJXBhdGhzKSxjKCdwdmFsJywnbGVhZGluZ0VkZ2UnLCdORVMnLCdjb21wJywncGF0aHdheScpXSwKICAgICAgICAgZW5yR1t3aGljaChlbnJHJHBhdGh3YXklaW4lcGF0aHMpLGMoJ3B2YWwnLCdsZWFkaW5nRWRnZScsJ05FUycsJ2NvbXAnLCdwYXRod2F5JyldKQpyYlt3aGljaChyYiRwYWRqPj0wLjEpLCdORVMnXT1OQQpyYiRwYXRod2F5IDwtIGdzdWIoIktFR0ciLCAiIixyYiRwYXRod2F5KQpyYiRwYXRod2F5IDwtIGdzdWIoIl8iLCAiICIscmIkcGF0aHdheSkKc3MgID0gc3Ryc3BsaXQoYXMuY2hhcmFjdGVyKHJiJGxlYWRpbmdFZGdlKSwnLCcpCnJiJG5fZ2VuZXMgPSB1bmxpc3QobGFwcGx5KHNzLGxlbmd0aCkpCnJiJHB2YWwgPC0gYXMubnVtZXJpYyhyYiRwdmFsKQpyYlt3aGljaChyYiRwdmFsPj0wLjEpLCdwdmFsJ109TkEKZ2dwbG90KG5hLm9taXQocmIpLGFlcyhwYXRod2F5LGNvbXAsZmlsbD1ORVMpKStnZW9tX3BvaW50KGFlcyhzaXplPXB2YWwpLHNoYXBlPTIxKStzY2FsZV94X2Rpc2NyZXRlKGxhYmVsID0gZnVuY3Rpb24oeCkgc3RyaW5ncjo6c3RyX3RydW5jKHgsNTApKSt0aGVtZV9idygpK2Nvb3JkX2ZsaXAoKSt0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoIGFuZ2xlPTYwLGhqdXN0PTEpKStzY2FsZV9maWxsX2dyYWRpZW50bihjb2xvcnM9cmV2KGJyZXdlci5wYWwoMTEsJ1JkWWxCdScpKSkrIHNjYWxlX3NpemUodHJhbnMgPSAncmV2ZXJzZScpKyB0aGVtZShheGlzLnRleHQgPSBlbGVtZW50X3RleHQoZmFjZT0iYm9sZCIpKQoKYGBgCgoKIyBQbG90IHRoZSBvdmVybGFwIGJldHdlZW4gREVHcyB3aXRoIGFuIHVwc2V0IHBsb3QvVmVubiBEaWFncmFtCgojIyBPdmVybGFwIG9mIERFR3MgaW4gY29tcGFyYWlzb25zIHsudGFic2V0fQpgYGB7ciAgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBwYWdlZC5wcmludD1UUlVFfQpyZXM9cmJpbmQocmVzQSxyZXNCLHJlc0MscmVzRCxyZXNFLHJlc0YscmVzRykKcmVzPSBuYS5vbWl0KHJlcykKCmRlZ3NMaXN0dnMgPSBsaXN0KAogIFdNTF92c19OQVdNPXN1YnNldChyZXMsY29tcD09J1dNTF92c19OQVdNJyAmIGFkai5QLlZhbDwwLjEgJiBhYnMobG9nRkMpPjEpJGdlbmVfbmFtZSwKICAgIFBWTUxfdnNfV01MPXN1YnNldChyZXMsY29tcD09J1BWTUxfdnNfV01MJyAmIGFkai5QLlZhbDwwLjEgJiBhYnMobG9nRkMpPjEpJGdlbmVfbmFtZSwKICAgIFBWTUxfdnNfTkFXTT1zdWJzZXQocmVzLGNvbXA9PSdQVk1MX3ZzX05BV00nICYgYWRqLlAuVmFsPDAuMSAmIGFicyhsb2dGQyk+MSkkZ2VuZV9uYW1lLAogICAgV01MX3ZzX0NMPXN1YnNldChyZXMsY29tcD09J1dNTF92c19DTCcgJiBhZGouUC5WYWw8MC4xICYgYWJzKGxvZ0ZDKT4xKSRnZW5lX25hbWUsCiAgICBOQVdNX3ZzX05BR009c3Vic2V0KHJlcyxjb21wPT0nTkFXTV92c19OQUdNJyAmIGFkai5QLlZhbDwwLjEgJiBhYnMobG9nRkMpPjEpJGdlbmVfbmFtZSkKCmRlZ3NMaXN0VVAgPSBsaXN0KAogIFdNTF92c19OQVdNPXN1YnNldChyZXMsY29tcD09J1dNTF92c19OQVdNJyAmIGFkai5QLlZhbDwwLjEgJiAobG9nRkMpPjEpJGdlbmVfbmFtZSwKICAgIFBWTUxfdnNfV01MPXN1YnNldChyZXMsY29tcD09J1BWTUxfdnNfV01MJyAmIGFkai5QLlZhbDwwLjEgJiAobG9nRkMpPjEpJGdlbmVfbmFtZSwKICAgIFBWTUxfdnNfTkFXTT1zdWJzZXQocmVzLGNvbXA9PSdQVk1MX3ZzX05BV00nICYgYWRqLlAuVmFsPDAuMSAmIChsb2dGQyk+MSkkZ2VuZV9uYW1lLAogICAgV01MX3ZzX0NMPXN1YnNldChyZXMsY29tcD09J1dNTF92c19DTCcgJiBhZGouUC5WYWw8MC4xICYgKGxvZ0ZDKT4xKSRnZW5lX25hbWUsCiAgICBOQVdNX3ZzX05BR009c3Vic2V0KHJlcyxjb21wPT0nTkFXTV92c19OQUdNJyAmIGFkai5QLlZhbDwwLjEgJiAobG9nRkMpPjEpJGdlbmVfbmFtZSkKCmRlZ3NMaXN0RE9XTiA9IGxpc3QoCiAgV01MX3ZzX05BV009c3Vic2V0KHJlcyxjb21wPT0nV01MX3ZzX05BV00nICYgYWRqLlAuVmFsPDAuMSAmIChsb2dGQyk8MSkkZ2VuZV9uYW1lLAogICAgUFZNTF92c19XTUw9c3Vic2V0KHJlcyxjb21wPT0nUFZNTF92c19XTUwnICYgYWRqLlAuVmFsPDAuMSAmIChsb2dGQyk8MSkkZ2VuZV9uYW1lLAogICAgUFZNTF92c19OQVdNPXN1YnNldChyZXMsY29tcD09J1BWTUxfdnNfTkFXTScgJiBhZGouUC5WYWw8MC4xICYgKGxvZ0ZDKTwxKSRnZW5lX25hbWUsCiAgICBXTUxfdnNfQ0w9c3Vic2V0KHJlcyxjb21wPT0nV01MX3ZzX0NMJyAmIGFkai5QLlZhbDwwLjEgJiAobG9nRkMpPDEpJGdlbmVfbmFtZSwKICAgIE5BV01fdnNfTkFHTT1zdWJzZXQocmVzLGNvbXA9PSdOQVdNX3ZzX05BR00nICYgYWRqLlAuVmFsPDAuMSAmIChsb2dGQyk8MSkkZ2VuZV9uYW1lKQoKYGBgCgoKIyMjIFVwU2V0IHBsb3QKYGBge3IgIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcGFnZWQucHJpbnQ9VFJVRSwgZmlnLndpZHRoID0gOCwgZmlnLmhlaWdodCA9IDYsZmlnLmtlZXAgPSAibGFzdCJ9CnVwc2V0KGZyb21MaXN0KGRlZ3NMaXN0dnMpLHNldHMgPSBjKCdXTUxfdnNfTkFXTScsJ1BWTUxfdnNfV01MJywnUFZNTF92c19OQVdNJywiV01MX3ZzX0NMIiwiTkFXTV92c19OQUdNIiksb3JkZXIuYnk9J2ZyZXEnLGRlY3JlYXNpbmcgPSBjKEYpLHRleHQuc2NhbGUgPSBjKDEuMywgMiwgMS41LCAxLjUsIDIsIDIpKQojdXBzZXQoZnJvbUxpc3QoZGVnc0xpc3RVUCksc2V0cyA9IGMoJ1dNTF92c19OQVdNJywnUFZNTF92c19XTUwnLCdQVk1MX3ZzX05BV00nLCJXTUxfdnNfQ0wiLCJOQVdNX3ZzX05BR00iKSxvcmRlci5ieT0nZnJlcScsZGVjcmVhc2luZyA9IGMoRiksdGV4dC5zY2FsZSA9IGMoMS4zLCAyLCAxLjUsIDEuNSwgMiwgMikpCiN1cHNldChmcm9tTGlzdChkZWdzTGlzdERPV04pLHNldHMgPSBjKCdXTUxfdnNfTkFXTScsJ1BWTUxfdnNfV01MJywnUFZNTF92c19OQVdNJywiV01MX3ZzX0NMIiwiTkFXTV92c19OQUdNIiksb3JkZXIuYnk9J2ZyZXEnLGRlY3JlYXNpbmcgPSBjKEYpLHRleHQuc2NhbGUgPSBjKDEuMywgMiwgMS41LCAxLjUsIDIsIDIpKQpgYGAKCiMjIyBWZW5uIERpYWdyYW0KYGBge3IgIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcGFnZWQucHJpbnQ9VFJVRSwgZmlnLndpZHRoID0gOCwgZmlnLmhlaWdodCA9IDZ9CiNsYWJlbCA9ICJjb3VudCIKZ2dWZW5uRGlhZ3JhbShkZWdzTGlzdHZzLGxhYmVsID0gInBlcmNlbnQiLCBsYWJlbF9hbHBoYSA9IDApKyBzY2FsZV9maWxsX2Rpc3RpbGxlcihwYWxldHRlID0gIlJlZHMiLCBkaXJlY3Rpb24gPSAxKQpgYGAKCiMgR2VuZSBPbnRvbG9neSBlbnJpY2htZW50IGFuYWx5c2lzIG9mIG92ZXJsYXBwaW5nIGdlbmVzIGluIGNvbXBhcmlzb25zIGJldHdlZW4gY29uZGl0aW9ucyhUaGUgdG9wIDUgc3BlY2lmaWMgR2VuZXNldHMgZnJvbSB0aGUgdXBzZXRzIHBsb3QpIHsudGFic2V0fSAKCmBgYHtyIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcGFnZWQucHJpbnQ9VFJVRX0KV01MX3ZzX05BV009bmEub21pdChzdWJzZXQocmVzLGNvbXA9PSdXTUxfdnNfTkFXTScgJiBhZGouUC5WYWw8MC4xICYgYWJzKGxvZ0ZDKT4xKSRnZW5lX25hbWUpClBWTUxfdnNfV01MPW5hLm9taXQoc3Vic2V0KHJlcyxjb21wPT0nUFZNTF92c19XTUwnICYgYWRqLlAuVmFsPDAuMSAmIGFicyhsb2dGQyk+MSkkZ2VuZV9uYW1lKQpQVk1MX3ZzX05BV009bmEub21pdChzdWJzZXQocmVzLGNvbXA9PSdQVk1MX3ZzX05BV00nICYgYWRqLlAuVmFsPDAuMSAmIGFicyhsb2dGQyk+MSkkZ2VuZV9uYW1lKQpDTF92c19OQVdNPW5hLm9taXQoc3Vic2V0KHJlcyxjb21wPT0nQ0xfdnNfTkFXTScgJiBhZGouUC5WYWw8MC4xICYgYWJzKGxvZ0ZDKT4xKSRnZW5lX25hbWUpCldNTF92c19DTD1uYS5vbWl0KHN1YnNldChyZXMsY29tcD09J1dNTF92c19DTCcgJiBhZGouUC5WYWw8MC4xICYgYWJzKGxvZ0ZDKT4xKSRnZW5lX25hbWUpCk5BV01fdnNfTkFHTT1uYS5vbWl0KHN1YnNldChyZXMsY29tcD09J05BV01fdnNfTkFHTScgJiBhZGouUC5WYWw8MC4xICYgYWJzKGxvZ0ZDKT4xKSRnZW5lX25hbWUpCgpzcGVjaWZpY1dNTF92c19DTCA9IGFzLmNoYXJhY3RlcihXTUxfdnNfQ0xbIVdNTF92c19DTCVpbiVXTUxfdnNfTkFXTSAmICFXTUxfdnNfQ0wlaW4lUFZNTF92c19XTUwgJiAhV01MX3ZzX0NMJWluJVBWTUxfdnNfTkFXTSAmICFXTUxfdnNfQ0wlaW4lQ0xfdnNfTkFXTSAmICFXTUxfdnNfQ0wlaW4lTkFXTV92c19OQUdNXSkKCnNwZWNpZmljUFZNTF92c19OQVdNID0gYXMuY2hhcmFjdGVyKFBWTUxfdnNfTkFXTVshUFZNTF92c19OQVdNJWluJVdNTF92c19OQVdNICYgIVBWTUxfdnNfTkFXTSVpbiVQVk1MX3ZzX1dNTCAmICFQVk1MX3ZzX05BV00laW4lV01MX3ZzX0NMICYgIVBWTUxfdnNfTkFXTSVpbiVDTF92c19OQVdNICYgIVBWTUxfdnNfTkFXTSVpbiVOQVdNX3ZzX05BR01dKQoKY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MID0gYXMuY2hhcmFjdGVyKFBWTUxfdnNfTkFXTVshUFZNTF92c19OQVdNJWluJVdNTF92c19OQVdNICYgUFZNTF92c19OQVdNJWluJVBWTUxfdnNfV01MICYgIVBWTUxfdnNfTkFXTSVpbiVXTUxfdnNfQ0wgJiAhUFZNTF92c19OQVdNJWluJUNMX3ZzX05BV00gJiAhUFZNTF92c19OQVdNJWluJU5BV01fdnNfTkFHTV0pCgpjb21tb25QVk1MX3ZzX05BV00uUFZNTF92c19XTUwuV01MX3ZzX0NMID0gYXMuY2hhcmFjdGVyKFBWTUxfdnNfTkFXTVshUFZNTF92c19OQVdNJWluJVdNTF92c19OQVdNICYgUFZNTF92c19OQVdNJWluJVBWTUxfdnNfV01MICYgUFZNTF92c19OQVdNJWluJVdNTF92c19DTCAmICFQVk1MX3ZzX05BV00laW4lQ0xfdnNfTkFXTSAmICFQVk1MX3ZzX05BV00laW4lTkFXTV92c19OQUdNXSkKICAKY29tbW9uUFZNTF92c19OQVdNLldNTF92c19DTCA9IGFzLmNoYXJhY3RlcihQVk1MX3ZzX05BV01bIVBWTUxfdnNfTkFXTSVpbiVXTUxfdnNfTkFXTSAmICFQVk1MX3ZzX05BV00laW4lUFZNTF92c19XTUwgJiBQVk1MX3ZzX05BV00laW4lV01MX3ZzX0NMICYgIVBWTUxfdnNfTkFXTSVpbiVDTF92c19OQVdNICYgIVBWTUxfdnNfTkFXTSVpbiVOQVdNX3ZzX05BR01dKQoKbGlzdCA9IGxpc3QoY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MPWNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTCwgc3BlY2lmaWNXTUxfdnNfQ0w9c3BlY2lmaWNXTUxfdnNfQ0wsc3BlY2lmaWNQVk1MX3ZzX05BV009c3BlY2lmaWNQVk1MX3ZzX05BV00sIGNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTC5XTUxfdnNfQ0w9Y29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MLldNTF92c19DTCwgY29tbW9uUFZNTF92c19OQVdNLldNTF92c19DTD1jb21tb25QVk1MX3ZzX05BV00uV01MX3ZzX0NMICkKCmZpc2hCUCA9IGZpc2hlcl9lbnJpY2htZW50KGxpc3QsZ28sdW5pcXVlKHJlZl9HJFNZTUJPTCkpCmZpc2hNRiA9IGZpc2hlcl9lbnJpY2htZW50KGxpc3QsbWYsdW5pcXVlKHJlZl9HJFNZTUJPTCkpCmZpc2hURlQgPSBmaXNoZXJfZW5yaWNobWVudChsaXN0LHRmdCx1bmlxdWUocmVmX0ckU1lNQk9MKSkKZmlzaEtFR0cgPSBmaXNoZXJfZW5yaWNobWVudChsaXN0LGtlZ2csdW5pcXVlKHJlZl9HJFNZTUJPTCkpCmBgYAoKIyMgYmlvbG9naWNhbCBwcm9jZXNzZXMgey50YWJzZXR9CmBgYHtyIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcGFnZWQucHJpbnQ9VFJVRSwgZmlnLndpZHRoID0gMTAsIGZpZy5oZWlnaHQgPSA4fQogIGVuci5zcGVjaWZpY1dNTF92c19DTCA9IGZpc2hCUCRzcGVjaWZpY1dNTF92c19DTAogIGVuci5zcGVjaWZpY1dNTF92c19DTCRwYXRod2F5ID0gcm93bmFtZXMoZW5yLnNwZWNpZmljV01MX3ZzX0NMKQogIGVuci5zcGVjaWZpY1dNTF92c19DTCRmZHIgPC0gYXMubnVtZXJpYyhlbnIuc3BlY2lmaWNXTUxfdnNfQ0wkZmRyKSAKICBlbnIuc3BlY2lmaWNXTUxfdnNfQ0wkT1Iub2Rkcy5yYXRpbyA8LSBhcy5udW1lcmljKGVuci5zcGVjaWZpY1dNTF92c19DTCRPUi5vZGRzLnJhdGlvKSAKICBlbnIuc3BlY2lmaWNXTUxfdnNfQ0wkTk9NX3B2YWwgPC0gYXMubnVtZXJpYyhlbnIuc3BlY2lmaWNXTUxfdnNfQ0wkTk9NX3B2YWwpCiAgdG9wc3BlY2lmaWNXTUxfdnNfQ0wgPC0gdG9wUGF0aChmaXNoQlAgLCJzcGVjaWZpY1dNTF92c19DTCIsIDAuNSwgMjApCiAgZW5yLnNwZWNpZmljV01MX3ZzX0NMIDwtIGVuci5zcGVjaWZpY1dNTF92c19DTFttYXRjaCh0b3BzcGVjaWZpY1dNTF92c19DTCwgcm93bmFtZXMoZW5yLnNwZWNpZmljV01MX3ZzX0NMKSksXQogIHJvd25hbWVzKGVuci5zcGVjaWZpY1dNTF92c19DTCkgPC0gZ3N1YigiR09CUF8iLCAiIixyb3duYW1lcyhlbnIuc3BlY2lmaWNXTUxfdnNfQ0wpKSAKICBlbnIuc3BlY2lmaWNXTUxfdnNfQ0w9ZW5yLnNwZWNpZmljV01MX3ZzX0NMW29yZGVyKGVuci5zcGVjaWZpY1dNTF92c19DTCROT01fcHZhbCksXQogIGVuci5zcGVjaWZpY1dNTF92c19DTCRjb21wID0gInNwZWNpZmljV01MX3ZzX0NMIgogIAogIGVuci5zcGVjaWZpY1BWTUxfdnNfTkFXTSA9IGZpc2hCUCRzcGVjaWZpY1BWTUxfdnNfTkFXTQogIGVuci5zcGVjaWZpY1BWTUxfdnNfTkFXTSRwYXRod2F5ID0gcm93bmFtZXMoZW5yLnNwZWNpZmljUFZNTF92c19OQVdNKQogIGVuci5zcGVjaWZpY1BWTUxfdnNfTkFXTSRmZHIgPC0gYXMubnVtZXJpYyhlbnIuc3BlY2lmaWNQVk1MX3ZzX05BV00kZmRyKSAKICBlbnIuc3BlY2lmaWNQVk1MX3ZzX05BV00kT1Iub2Rkcy5yYXRpbyA8LSBhcy5udW1lcmljKGVuci5zcGVjaWZpY1BWTUxfdnNfTkFXTSRPUi5vZGRzLnJhdGlvKSAKICBlbnIuc3BlY2lmaWNQVk1MX3ZzX05BV00kTk9NX3B2YWwgPC0gYXMubnVtZXJpYyhlbnIuc3BlY2lmaWNQVk1MX3ZzX05BV00kTk9NX3B2YWwpCiAgdG9wc3BlY2lmaWNQVk1MX3ZzX05BV00gPC0gdG9wUGF0aChmaXNoQlAgLCJzcGVjaWZpY1BWTUxfdnNfTkFXTSIsIDAuNSwgMjApCiAgZW5yLnNwZWNpZmljUFZNTF92c19OQVdNIDwtIGVuci5zcGVjaWZpY1BWTUxfdnNfTkFXTVttYXRjaCh0b3BzcGVjaWZpY1BWTUxfdnNfTkFXTSwgcm93bmFtZXMoZW5yLnNwZWNpZmljUFZNTF92c19OQVdNKSksXQogIHJvd25hbWVzKGVuci5zcGVjaWZpY1BWTUxfdnNfTkFXTSkgPC0gZ3N1YigiR09CUF8iLCAiIixyb3duYW1lcyhlbnIuc3BlY2lmaWNQVk1MX3ZzX05BV00pKSAKICBlbnIuc3BlY2lmaWNQVk1MX3ZzX05BV009ZW5yLnNwZWNpZmljUFZNTF92c19OQVdNW29yZGVyKGVuci5zcGVjaWZpY1BWTUxfdnNfTkFXTSROT01fcHZhbCksXQogIGVuci5zcGVjaWZpY1BWTUxfdnNfTkFXTSRjb21wID0gInNwZWNpZmljUFZNTF92c19OQVdNIgogIAogIGVuci5jb21tb25QVk1MX3ZzX05BV00uUFZNTF92c19XTUwgPSBmaXNoQlAkY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MCiAgZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTCRwYXRod2F5ID0gcm93bmFtZXMoZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTCkKICBlbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MJGZkciA8LSBhcy5udW1lcmljKGVuci5jb21tb25QVk1MX3ZzX05BV00uUFZNTF92c19XTUwkZmRyKSAKICBlbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MJE9SLm9kZHMucmF0aW8gPC0gYXMubnVtZXJpYyhlbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MJE9SLm9kZHMucmF0aW8pIAogIGVuci5jb21tb25QVk1MX3ZzX05BV00uUFZNTF92c19XTUwkTk9NX3B2YWwgPC0gYXMubnVtZXJpYyhlbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MJE5PTV9wdmFsKQogIHRvcGNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTCA8LSB0b3BQYXRoKGZpc2hCUCAsImNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTCIsIDAuNSwgMjApCiAgZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTCA8LSBlbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MW21hdGNoKHRvcGNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTCwgcm93bmFtZXMoZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTCkpLF0KICByb3duYW1lcyhlbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MKSA8LSBnc3ViKCJHT0JQXyIsICIiLHJvd25hbWVzKGVuci5jb21tb25QVk1MX3ZzX05BV00uUFZNTF92c19XTUwpKSAKICBlbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MPWVuci5jb21tb25QVk1MX3ZzX05BV00uUFZNTF92c19XTUxbb3JkZXIoZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTCROT01fcHZhbCksXQogIGVuci5jb21tb25QVk1MX3ZzX05BV00uUFZNTF92c19XTUwkY29tcCA9ICJjb21tb25QVk1MX3ZzX05BV00gJiBQVk1MX3ZzX1dNTCIKICAKICBlbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MLldNTF92c19DTCA9IGZpc2hCUCRjb21tb25QVk1MX3ZzX05BV00uUFZNTF92c19XTUwuV01MX3ZzX0NMCiAgZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTC5XTUxfdnNfQ0wkcGF0aHdheSA9IHJvd25hbWVzKGVuci5jb21tb25QVk1MX3ZzX05BV00uUFZNTF92c19XTUwuV01MX3ZzX0NMKQogIGVuci5jb21tb25QVk1MX3ZzX05BV00uUFZNTF92c19XTUwuV01MX3ZzX0NMJGZkciA8LSBhcy5udW1lcmljKGVuci5jb21tb25QVk1MX3ZzX05BV00uUFZNTF92c19XTUwuV01MX3ZzX0NMJGZkcikgCiAgZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTC5XTUxfdnNfQ0wkT1Iub2Rkcy5yYXRpbyA8LSBhcy5udW1lcmljKGVuci5jb21tb25QVk1MX3ZzX05BV00uUFZNTF92c19XTUwuV01MX3ZzX0NMJE9SLm9kZHMucmF0aW8pIAogIGVuci5jb21tb25QVk1MX3ZzX05BV00uUFZNTF92c19XTUwuV01MX3ZzX0NMJE5PTV9wdmFsIDwtIGFzLm51bWVyaWMoZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTC5XTUxfdnNfQ0wkTk9NX3B2YWwpCiAgdG9wY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MLldNTF92c19DTCA8LSB0b3BQYXRoKGZpc2hCUCAsImNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTC5XTUxfdnNfQ0wiLCAwLjUsMjApCiAgZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTC5XTUxfdnNfQ0wgPC0gZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTC5XTUxfdnNfQ0xbbWF0Y2godG9wY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MLldNTF92c19DTCwgcm93bmFtZXMoZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTC5XTUxfdnNfQ0wpKSxdCiAgcm93bmFtZXMoZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTC5XTUxfdnNfQ0wpIDwtIGdzdWIoIkdPQlBfIiwgIiIscm93bmFtZXMoZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTC5XTUxfdnNfQ0wpKSAKICBlbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MLldNTF92c19DTD1lbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MLldNTF92c19DTFtvcmRlcihlbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MLldNTF92c19DTCROT01fcHZhbCksXQogIGVuci5jb21tb25QVk1MX3ZzX05BV00uUFZNTF92c19XTUwuV01MX3ZzX0NMJGNvbXAgPSAiY29tbW9uUFZNTF92c19OQVdNICYgUFZNTF92c19XTUwgJiBXTUxfdnNfQ0wiCgogIGVuci5jb21tb25QVk1MX3ZzX05BV00uV01MX3ZzX0NMID0gZmlzaEJQJGNvbW1vblBWTUxfdnNfTkFXTS5XTUxfdnNfQ0wKICBlbnIuY29tbW9uUFZNTF92c19OQVdNLldNTF92c19DTCRwYXRod2F5ID0gcm93bmFtZXMoZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5XTUxfdnNfQ0wpCiAgZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5XTUxfdnNfQ0wkZmRyIDwtIGFzLm51bWVyaWMoZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5XTUxfdnNfQ0wkZmRyKSAKICBlbnIuY29tbW9uUFZNTF92c19OQVdNLldNTF92c19DTCRPUi5vZGRzLnJhdGlvIDwtIGFzLm51bWVyaWMoZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5XTUxfdnNfQ0wkT1Iub2Rkcy5yYXRpbykgCiAgZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5XTUxfdnNfQ0wkTk9NX3B2YWwgPC0gYXMubnVtZXJpYyhlbnIuY29tbW9uUFZNTF92c19OQVdNLldNTF92c19DTCROT01fcHZhbCkKICB0b3Bjb21tb25QVk1MX3ZzX05BV00uV01MX3ZzX0NMIDwtIHRvcFBhdGgoZmlzaEJQICwiY29tbW9uUFZNTF92c19OQVdNLldNTF92c19DTCIsIDAuNSwyMCkKICBlbnIuY29tbW9uUFZNTF92c19OQVdNLldNTF92c19DTCA8LSBlbnIuY29tbW9uUFZNTF92c19OQVdNLldNTF92c19DTFttYXRjaCh0b3Bjb21tb25QVk1MX3ZzX05BV00uV01MX3ZzX0NMLCByb3duYW1lcyhlbnIuY29tbW9uUFZNTF92c19OQVdNLldNTF92c19DTCkpLF0KICByb3duYW1lcyhlbnIuY29tbW9uUFZNTF92c19OQVdNLldNTF92c19DTCkgPC0gZ3N1YigiR09CUF8iLCAiIixyb3duYW1lcyhlbnIuY29tbW9uUFZNTF92c19OQVdNLldNTF92c19DTCkpIAogIGVuci5jb21tb25QVk1MX3ZzX05BV00uV01MX3ZzX0NMPWVuci5jb21tb25QVk1MX3ZzX05BV00uV01MX3ZzX0NMW29yZGVyKGVuci5jb21tb25QVk1MX3ZzX05BV00uV01MX3ZzX0NMJE5PTV9wdmFsKSxdCiAgZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5XTUxfdnNfQ0wkY29tcCA9ICJjb21tb25QVk1MX3ZzX05BV00gJiBQVk1MX3ZzX1dNTCIgIAoKYGBgCgoKIyMjIFNwZWNpZmljIFdNTF92c19DTApgYGB7ciBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIHBhZ2VkLnByaW50PVRSVUUsIGZpZy53aWR0aCA9IDEwLCBmaWcuaGVpZ2h0ID0gOH0KZ2dwbG90KGVuci5zcGVjaWZpY1dNTF92c19DTCwgYWVzKHg9cmVvcmRlcihyb3duYW1lcyhlbnIuc3BlY2lmaWNXTUxfdnNfQ0wpLC1yYW5rKE5PTV9wdmFsKSksIHk9LWxvZzEwKE5PTV9wdmFsKSxmaWxsPS1sb2cxMChOT01fcHZhbCkpKSArIGdlb21fY29sKHdpZHRoPS42NSkrIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93PSIjRjZCREMwIixoaWdoPSIjREMxQzEzIikgK3RoZW1lKGF4aXMudGV4dD1lbGVtZW50X3RleHQoc2l6ZT04KSkgKyBzY2FsZV94X2Rpc2NyZXRlKGxhYmVsID0gZnVuY3Rpb24oeCkgc3RyaW5ncjo6c3RyX3dyYXAoZ3N1YigiXyIsICIgIix4KSwgd2lkdGggPSAzMCkpICsgbGFicyh0aXRsZSA9ICJXTUxfdnNfQ0wiKSArIHhsYWIoIiIpICsgY29vcmRfZmxpcCgpICsgdGhlbWVfYncoKSsgdGhlbWUoYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KGZhY2U9ImJvbGQiKSkKYGBgCgojIyMgU3BlY2lmaWMgUFZNTF92c19OQVdNCmBgYHtyIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcGFnZWQucHJpbnQ9VFJVRSwgZmlnLndpZHRoID0gMTAsIGZpZy5oZWlnaHQgPSA4fQpnZ3Bsb3QoZW5yLnNwZWNpZmljUFZNTF92c19OQVdNLCBhZXMoeD1yZW9yZGVyKHJvd25hbWVzKGVuci5zcGVjaWZpY1BWTUxfdnNfTkFXTSksLXJhbmsoTk9NX3B2YWwpKSwgeT0tbG9nMTAoTk9NX3B2YWwpLGZpbGw9LWxvZzEwKE5PTV9wdmFsKSkpICsgZ2VvbV9jb2wod2lkdGg9LjY1KSsgc2NhbGVfZmlsbF9ncmFkaWVudChsb3c9IiNGNkJEQzAiLGhpZ2g9IiNEQzFDMTMiKSArdGhlbWUoYXhpcy50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTgpKSArIHNjYWxlX3hfZGlzY3JldGUobGFiZWwgPSBmdW5jdGlvbih4KSBzdHJpbmdyOjpzdHJfd3JhcChnc3ViKCJfIiwgIiAiLHgpLCB3aWR0aCA9IDMwKSkgKyBsYWJzKHRpdGxlID0gIlBWTUxfdnNfTkFXTSIpICsgeGxhYigiIikgKyBjb29yZF9mbGlwKCkgKyB0aGVtZV9idygpKyB0aGVtZShheGlzLnRleHQgPSBlbGVtZW50X3RleHQoZmFjZT0iYm9sZCIpKQpgYGAKCiMjIyBDb21tb24gUFZNTF92c19OQVdNICYgUFZNTF92c19XTUwKYGBge3IgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBwYWdlZC5wcmludD1UUlVFLCBmaWcud2lkdGggPSAxMCwgZmlnLmhlaWdodCA9IDh9CmdncGxvdChlbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MLCBhZXMoeD1yZW9yZGVyKHJvd25hbWVzKGVuci5jb21tb25QVk1MX3ZzX05BV00uUFZNTF92c19XTUwpLC1yYW5rKE5PTV9wdmFsKSksIHk9LWxvZzEwKE5PTV9wdmFsKSxmaWxsPS1sb2cxMChOT01fcHZhbCkpKSArIGdlb21fY29sKHdpZHRoPS42NSkrIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93PSIjRjZCREMwIixoaWdoPSIjREMxQzEzIikgK3RoZW1lKGF4aXMudGV4dD1lbGVtZW50X3RleHQoc2l6ZT04KSkgKyBzY2FsZV94X2Rpc2NyZXRlKGxhYmVsID0gZnVuY3Rpb24oeCkgc3RyaW5ncjo6c3RyX3dyYXAoZ3N1YigiXyIsICIgIix4KSwgd2lkdGggPSAzMCkpICsgbGFicyh0aXRsZSA9ICJjb21tb24gUFZNTF92c19OQVdNICYgUFZNTF92c19XTUwiKSArIHhsYWIoIiIpICsgY29vcmRfZmxpcCgpICsgdGhlbWVfYncoKSsgdGhlbWUoYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KGZhY2U9ImJvbGQiKSkKYGBgCgojIyMgQ29tbW9uIFBWTUxfdnNfTkFXTSAmIFBWTUxfdnNfV01MICYgV01MX3ZzX0NMCmBgYHtyIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcGFnZWQucHJpbnQ9VFJVRSwgZmlnLndpZHRoID0gMTAsIGZpZy5oZWlnaHQgPSA4fQpnZ3Bsb3QoZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTC5XTUxfdnNfQ0wsIGFlcyh4PXJlb3JkZXIocm93bmFtZXMoZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTC5XTUxfdnNfQ0wpLC1yYW5rKE5PTV9wdmFsKSksIHk9LWxvZzEwKE5PTV9wdmFsKSxmaWxsPS1sb2cxMChOT01fcHZhbCkpKSArIGdlb21fY29sKHdpZHRoPS42NSkrIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93PSIjRjZCREMwIixoaWdoPSIjREMxQzEzIikgK3RoZW1lKGF4aXMudGV4dD1lbGVtZW50X3RleHQoc2l6ZT04KSkgKyBzY2FsZV94X2Rpc2NyZXRlKGxhYmVsID0gZnVuY3Rpb24oeCkgc3RyaW5ncjo6c3RyX3dyYXAoZ3N1YigiXyIsICIgIix4KSwgd2lkdGggPSAzMCkpICsgbGFicyh0aXRsZSA9ICJDb21tb24gUFZNTF92c19OQVdNICYgUFZNTF92c19XTUwgJiBXTUxfdnNfQ0wiKSArIHhsYWIoIiIpICsgY29vcmRfZmxpcCgpICsgdGhlbWVfYncoKSsgdGhlbWUoYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KGZhY2U9ImJvbGQiKSkKYGBgCgojIyMgQ29tbW9uIFBWTUxfdnNfTkFXTSAmIFdNTF92c19DTApgYGB7ciBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIHBhZ2VkLnByaW50PVRSVUUsIGZpZy53aWR0aCA9IDEwLCBmaWcuaGVpZ2h0ID0gOH0KZ2dwbG90KGVuci5jb21tb25QVk1MX3ZzX05BV00uV01MX3ZzX0NMLCBhZXMoeD1yZW9yZGVyKHJvd25hbWVzKGVuci5jb21tb25QVk1MX3ZzX05BV00uV01MX3ZzX0NMKSwtcmFuayhOT01fcHZhbCkpLCB5PS1sb2cxMChOT01fcHZhbCksZmlsbD0tbG9nMTAoTk9NX3B2YWwpKSkgKyBnZW9tX2NvbCh3aWR0aD0uNjUpKyBzY2FsZV9maWxsX2dyYWRpZW50KGxvdz0iI0Y2QkRDMCIsaGlnaD0iI0RDMUMxMyIpICt0aGVtZShheGlzLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9OCkpICsgc2NhbGVfeF9kaXNjcmV0ZShsYWJlbCA9IGZ1bmN0aW9uKHgpIHN0cmluZ3I6OnN0cl93cmFwKGdzdWIoIl8iLCAiICIseCksIHdpZHRoID0gMzApKSArIGxhYnModGl0bGUgPSAiQ29tbW9uIFBWTUxfdnNfTkFXTSAmIFdNTF92c19DTCIpICsgeGxhYigiIikgKyBjb29yZF9mbGlwKCkgKyB0aGVtZV9idygpKyB0aGVtZShheGlzLnRleHQgPSBlbGVtZW50X3RleHQoZmFjZT0iYm9sZCIpKQpgYGAKCiMjIE1vbGVjdWxhciBGdW5jdGlvbiB7LnRhYnNldH0KYGBge3IgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBwYWdlZC5wcmludD1UUlVFLCBmaWcud2lkdGggPSAxMCwgZmlnLmhlaWdodCA9IDh9CiAgZW5yLnNwZWNpZmljV01MX3ZzX0NMID0gZmlzaE1GJHNwZWNpZmljV01MX3ZzX0NMCiAgZW5yLnNwZWNpZmljV01MX3ZzX0NMJHBhdGh3YXkgPSByb3duYW1lcyhlbnIuc3BlY2lmaWNXTUxfdnNfQ0wpCiAgZW5yLnNwZWNpZmljV01MX3ZzX0NMJGZkciA8LSBhcy5udW1lcmljKGVuci5zcGVjaWZpY1dNTF92c19DTCRmZHIpIAogIGVuci5zcGVjaWZpY1dNTF92c19DTCRPUi5vZGRzLnJhdGlvIDwtIGFzLm51bWVyaWMoZW5yLnNwZWNpZmljV01MX3ZzX0NMJE9SLm9kZHMucmF0aW8pIAogIGVuci5zcGVjaWZpY1dNTF92c19DTCROT01fcHZhbCA8LSBhcy5udW1lcmljKGVuci5zcGVjaWZpY1dNTF92c19DTCROT01fcHZhbCkKICB0b3BzcGVjaWZpY1dNTF92c19DTCA8LSB0b3BQYXRoKGZpc2hNRiAsInNwZWNpZmljV01MX3ZzX0NMIiwgMC41LCAyMCkKICBlbnIuc3BlY2lmaWNXTUxfdnNfQ0wgPC0gZW5yLnNwZWNpZmljV01MX3ZzX0NMW21hdGNoKHRvcHNwZWNpZmljV01MX3ZzX0NMLCByb3duYW1lcyhlbnIuc3BlY2lmaWNXTUxfdnNfQ0wpKSxdCiAgcm93bmFtZXMoZW5yLnNwZWNpZmljV01MX3ZzX0NMKSA8LSBnc3ViKCJHT01GXyIsICIiLHJvd25hbWVzKGVuci5zcGVjaWZpY1dNTF92c19DTCkpIAogIGVuci5zcGVjaWZpY1dNTF92c19DTD1lbnIuc3BlY2lmaWNXTUxfdnNfQ0xbb3JkZXIoZW5yLnNwZWNpZmljV01MX3ZzX0NMJE5PTV9wdmFsKSxdCiAgZW5yLnNwZWNpZmljV01MX3ZzX0NMJGNvbXAgPSAic3BlY2lmaWNXTUxfdnNfQ0wiCiAgCiAgZW5yLnNwZWNpZmljUFZNTF92c19OQVdNID0gZmlzaE1GJHNwZWNpZmljUFZNTF92c19OQVdNCiAgZW5yLnNwZWNpZmljUFZNTF92c19OQVdNJHBhdGh3YXkgPSByb3duYW1lcyhlbnIuc3BlY2lmaWNQVk1MX3ZzX05BV00pCiAgZW5yLnNwZWNpZmljUFZNTF92c19OQVdNJGZkciA8LSBhcy5udW1lcmljKGVuci5zcGVjaWZpY1BWTUxfdnNfTkFXTSRmZHIpIAogIGVuci5zcGVjaWZpY1BWTUxfdnNfTkFXTSRPUi5vZGRzLnJhdGlvIDwtIGFzLm51bWVyaWMoZW5yLnNwZWNpZmljUFZNTF92c19OQVdNJE9SLm9kZHMucmF0aW8pIAogIGVuci5zcGVjaWZpY1BWTUxfdnNfTkFXTSROT01fcHZhbCA8LSBhcy5udW1lcmljKGVuci5zcGVjaWZpY1BWTUxfdnNfTkFXTSROT01fcHZhbCkKICB0b3BzcGVjaWZpY1BWTUxfdnNfTkFXTSA8LSB0b3BQYXRoKGZpc2hNRiAsInNwZWNpZmljUFZNTF92c19OQVdNIiwgMC41LCAyMCkKICBlbnIuc3BlY2lmaWNQVk1MX3ZzX05BV00gPC0gZW5yLnNwZWNpZmljUFZNTF92c19OQVdNW21hdGNoKHRvcHNwZWNpZmljUFZNTF92c19OQVdNLCByb3duYW1lcyhlbnIuc3BlY2lmaWNQVk1MX3ZzX05BV00pKSxdCiAgcm93bmFtZXMoZW5yLnNwZWNpZmljUFZNTF92c19OQVdNKSA8LSBnc3ViKCJHT01GXyIsICIiLHJvd25hbWVzKGVuci5zcGVjaWZpY1BWTUxfdnNfTkFXTSkpIAogIGVuci5zcGVjaWZpY1BWTUxfdnNfTkFXTT1lbnIuc3BlY2lmaWNQVk1MX3ZzX05BV01bb3JkZXIoZW5yLnNwZWNpZmljUFZNTF92c19OQVdNJE5PTV9wdmFsKSxdCiAgZW5yLnNwZWNpZmljUFZNTF92c19OQVdNJGNvbXAgPSAic3BlY2lmaWNQVk1MX3ZzX05BV00iCiAgCiAgZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTCA9IGZpc2hNRiRjb21tb25QVk1MX3ZzX05BV00uUFZNTF92c19XTUwKICBlbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MJHBhdGh3YXkgPSByb3duYW1lcyhlbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MKQogIGVuci5jb21tb25QVk1MX3ZzX05BV00uUFZNTF92c19XTUwkZmRyIDwtIGFzLm51bWVyaWMoZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTCRmZHIpIAogIGVuci5jb21tb25QVk1MX3ZzX05BV00uUFZNTF92c19XTUwkT1Iub2Rkcy5yYXRpbyA8LSBhcy5udW1lcmljKGVuci5jb21tb25QVk1MX3ZzX05BV00uUFZNTF92c19XTUwkT1Iub2Rkcy5yYXRpbykgCiAgZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTCROT01fcHZhbCA8LSBhcy5udW1lcmljKGVuci5jb21tb25QVk1MX3ZzX05BV00uUFZNTF92c19XTUwkTk9NX3B2YWwpCiAgdG9wY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MIDwtIHRvcFBhdGgoZmlzaE1GICwiY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MIiwgMC41LCAyMCkKICBlbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MIDwtIGVuci5jb21tb25QVk1MX3ZzX05BV00uUFZNTF92c19XTUxbbWF0Y2godG9wY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MLCByb3duYW1lcyhlbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MKSksXQogIHJvd25hbWVzKGVuci5jb21tb25QVk1MX3ZzX05BV00uUFZNTF92c19XTUwpIDwtIGdzdWIoIkdPTUZfIiwgIiIscm93bmFtZXMoZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTCkpIAogIGVuci5jb21tb25QVk1MX3ZzX05BV00uUFZNTF92c19XTUw9ZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTFtvcmRlcihlbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MJE5PTV9wdmFsKSxdCiAgZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTCRjb21wID0gImNvbW1vblBWTUxfdnNfTkFXTSAmIFBWTUxfdnNfV01MIgogIAogIGVuci5jb21tb25QVk1MX3ZzX05BV00uUFZNTF92c19XTUwuV01MX3ZzX0NMID0gZmlzaE1GJGNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTC5XTUxfdnNfQ0wKICBlbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MLldNTF92c19DTCRwYXRod2F5ID0gcm93bmFtZXMoZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTC5XTUxfdnNfQ0wpCiAgZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTC5XTUxfdnNfQ0wkZmRyIDwtIGFzLm51bWVyaWMoZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTC5XTUxfdnNfQ0wkZmRyKSAKICBlbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MLldNTF92c19DTCRPUi5vZGRzLnJhdGlvIDwtIGFzLm51bWVyaWMoZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTC5XTUxfdnNfQ0wkT1Iub2Rkcy5yYXRpbykgCiAgZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTC5XTUxfdnNfQ0wkTk9NX3B2YWwgPC0gYXMubnVtZXJpYyhlbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MLldNTF92c19DTCROT01fcHZhbCkKICB0b3Bjb21tb25QVk1MX3ZzX05BV00uUFZNTF92c19XTUwuV01MX3ZzX0NMIDwtIHRvcFBhdGgoZmlzaE1GICwiY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MLldNTF92c19DTCIsIDAuNSwyMCkKICBlbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MLldNTF92c19DTCA8LSBlbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MLldNTF92c19DTFttYXRjaCh0b3Bjb21tb25QVk1MX3ZzX05BV00uUFZNTF92c19XTUwuV01MX3ZzX0NMLCByb3duYW1lcyhlbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MLldNTF92c19DTCkpLF0KICByb3duYW1lcyhlbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MLldNTF92c19DTCkgPC0gZ3N1YigiR09NRl8iLCAiIixyb3duYW1lcyhlbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MLldNTF92c19DTCkpIAogIGVuci5jb21tb25QVk1MX3ZzX05BV00uUFZNTF92c19XTUwuV01MX3ZzX0NMPWVuci5jb21tb25QVk1MX3ZzX05BV00uUFZNTF92c19XTUwuV01MX3ZzX0NMW29yZGVyKGVuci5jb21tb25QVk1MX3ZzX05BV00uUFZNTF92c19XTUwuV01MX3ZzX0NMJE5PTV9wdmFsKSxdCiAgZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTC5XTUxfdnNfQ0wkY29tcCA9ICJjb21tb25QVk1MX3ZzX05BV00gJiBQVk1MX3ZzX1dNTCAmIFdNTF92c19DTCIKCiAgZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5XTUxfdnNfQ0wgPSBmaXNoTUYkY29tbW9uUFZNTF92c19OQVdNLldNTF92c19DTAogIGVuci5jb21tb25QVk1MX3ZzX05BV00uV01MX3ZzX0NMJHBhdGh3YXkgPSByb3duYW1lcyhlbnIuY29tbW9uUFZNTF92c19OQVdNLldNTF92c19DTCkKICBlbnIuY29tbW9uUFZNTF92c19OQVdNLldNTF92c19DTCRmZHIgPC0gYXMubnVtZXJpYyhlbnIuY29tbW9uUFZNTF92c19OQVdNLldNTF92c19DTCRmZHIpIAogIGVuci5jb21tb25QVk1MX3ZzX05BV00uV01MX3ZzX0NMJE9SLm9kZHMucmF0aW8gPC0gYXMubnVtZXJpYyhlbnIuY29tbW9uUFZNTF92c19OQVdNLldNTF92c19DTCRPUi5vZGRzLnJhdGlvKSAKICBlbnIuY29tbW9uUFZNTF92c19OQVdNLldNTF92c19DTCROT01fcHZhbCA8LSBhcy5udW1lcmljKGVuci5jb21tb25QVk1MX3ZzX05BV00uV01MX3ZzX0NMJE5PTV9wdmFsKQogIHRvcGNvbW1vblBWTUxfdnNfTkFXTS5XTUxfdnNfQ0wgPC0gdG9wUGF0aChmaXNoTUYgLCJjb21tb25QVk1MX3ZzX05BV00uV01MX3ZzX0NMIiwgMC41LDIwKQogIGVuci5jb21tb25QVk1MX3ZzX05BV00uV01MX3ZzX0NMIDwtIGVuci5jb21tb25QVk1MX3ZzX05BV00uV01MX3ZzX0NMW21hdGNoKHRvcGNvbW1vblBWTUxfdnNfTkFXTS5XTUxfdnNfQ0wsIHJvd25hbWVzKGVuci5jb21tb25QVk1MX3ZzX05BV00uV01MX3ZzX0NMKSksXQogIHJvd25hbWVzKGVuci5jb21tb25QVk1MX3ZzX05BV00uV01MX3ZzX0NMKSA8LSBnc3ViKCJHT01GXyIsICIiLHJvd25hbWVzKGVuci5jb21tb25QVk1MX3ZzX05BV00uV01MX3ZzX0NMKSkgCiAgZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5XTUxfdnNfQ0w9ZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5XTUxfdnNfQ0xbb3JkZXIoZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5XTUxfdnNfQ0wkTk9NX3B2YWwpLF0KICBlbnIuY29tbW9uUFZNTF92c19OQVdNLldNTF92c19DTCRjb21wID0gImNvbW1vblBWTUxfdnNfTkFXTSAmIFBWTUxfdnNfV01MIiAgCgpgYGAKCgojIyMgU3BlY2lmaWMgV01MX3ZzX0NMCmBgYHtyIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcGFnZWQucHJpbnQ9VFJVRSwgZmlnLndpZHRoID0gMTAsIGZpZy5oZWlnaHQgPSA4fQpnZ3Bsb3QoZW5yLnNwZWNpZmljV01MX3ZzX0NMLCBhZXMoeD1yZW9yZGVyKHJvd25hbWVzKGVuci5zcGVjaWZpY1dNTF92c19DTCksLXJhbmsoTk9NX3B2YWwpKSwgeT0tbG9nMTAoTk9NX3B2YWwpLGZpbGw9LWxvZzEwKE5PTV9wdmFsKSkpICsgZ2VvbV9jb2wod2lkdGg9LjY1KSsgc2NhbGVfZmlsbF9ncmFkaWVudChsb3c9IiNGNkJEQzAiLGhpZ2g9IiNEQzFDMTMiKSArdGhlbWUoYXhpcy50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTgpKSArIHNjYWxlX3hfZGlzY3JldGUobGFiZWwgPSBmdW5jdGlvbih4KSBzdHJpbmdyOjpzdHJfd3JhcChnc3ViKCJfIiwgIiAiLHgpLCB3aWR0aCA9IDMwKSkgKyBsYWJzKHRpdGxlID0gIldNTF92c19DTCIpICsgeGxhYigiIikgKyBjb29yZF9mbGlwKCkgKyB0aGVtZV9idygpKyB0aGVtZShheGlzLnRleHQgPSBlbGVtZW50X3RleHQoZmFjZT0iYm9sZCIpKQpgYGAKCiMjIyBTcGVjaWZpYyBQVk1MX3ZzX05BV00KYGBge3IgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBwYWdlZC5wcmludD1UUlVFLCBmaWcud2lkdGggPSAxMCwgZmlnLmhlaWdodCA9IDh9CmdncGxvdChlbnIuc3BlY2lmaWNQVk1MX3ZzX05BV00sIGFlcyh4PXJlb3JkZXIocm93bmFtZXMoZW5yLnNwZWNpZmljUFZNTF92c19OQVdNKSwtcmFuayhOT01fcHZhbCkpLCB5PS1sb2cxMChOT01fcHZhbCksZmlsbD0tbG9nMTAoTk9NX3B2YWwpKSkgKyBnZW9tX2NvbCh3aWR0aD0uNjUpKyBzY2FsZV9maWxsX2dyYWRpZW50KGxvdz0iI0Y2QkRDMCIsaGlnaD0iI0RDMUMxMyIpICt0aGVtZShheGlzLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9OCkpICsgc2NhbGVfeF9kaXNjcmV0ZShsYWJlbCA9IGZ1bmN0aW9uKHgpIHN0cmluZ3I6OnN0cl93cmFwKGdzdWIoIl8iLCAiICIseCksIHdpZHRoID0gMzApKSArIGxhYnModGl0bGUgPSAiUFZNTF92c19OQVdNIikgKyB4bGFiKCIiKSArIGNvb3JkX2ZsaXAoKSArIHRoZW1lX2J3KCkrIHRoZW1lKGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChmYWNlPSJib2xkIikpCmBgYAoKIyMjIENvbW1vbiBQVk1MX3ZzX05BV00gJiBQVk1MX3ZzX1dNTApgYGB7ciBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIHBhZ2VkLnByaW50PVRSVUUsIGZpZy53aWR0aCA9IDEwLCBmaWcuaGVpZ2h0ID0gOH0KZ2dwbG90KGVuci5jb21tb25QVk1MX3ZzX05BV00uUFZNTF92c19XTUwsIGFlcyh4PXJlb3JkZXIocm93bmFtZXMoZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTCksLXJhbmsoTk9NX3B2YWwpKSwgeT0tbG9nMTAoTk9NX3B2YWwpLGZpbGw9LWxvZzEwKE5PTV9wdmFsKSkpICsgZ2VvbV9jb2wod2lkdGg9LjY1KSsgc2NhbGVfZmlsbF9ncmFkaWVudChsb3c9IiNGNkJEQzAiLGhpZ2g9IiNEQzFDMTMiKSArdGhlbWUoYXhpcy50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTgpKSArIHNjYWxlX3hfZGlzY3JldGUobGFiZWwgPSBmdW5jdGlvbih4KSBzdHJpbmdyOjpzdHJfd3JhcChnc3ViKCJfIiwgIiAiLHgpLCB3aWR0aCA9IDMwKSkgKyBsYWJzKHRpdGxlID0gImNvbW1vbiBQVk1MX3ZzX05BV00gJiBQVk1MX3ZzX1dNTCIpICsgeGxhYigiIikgKyBjb29yZF9mbGlwKCkgKyB0aGVtZV9idygpKyB0aGVtZShheGlzLnRleHQgPSBlbGVtZW50X3RleHQoZmFjZT0iYm9sZCIpKQpgYGAKCiMjIyBDb21tb24gUFZNTF92c19OQVdNICYgUFZNTF92c19XTUwgJiBXTUxfdnNfQ0wKYGBge3IgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBwYWdlZC5wcmludD1UUlVFLCBmaWcud2lkdGggPSAxMCwgZmlnLmhlaWdodCA9IDh9CmdncGxvdChlbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MLldNTF92c19DTCwgYWVzKHg9cmVvcmRlcihyb3duYW1lcyhlbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MLldNTF92c19DTCksLXJhbmsoTk9NX3B2YWwpKSwgeT0tbG9nMTAoTk9NX3B2YWwpLGZpbGw9LWxvZzEwKE5PTV9wdmFsKSkpICsgZ2VvbV9jb2wod2lkdGg9LjY1KSsgc2NhbGVfZmlsbF9ncmFkaWVudChsb3c9IiNGNkJEQzAiLGhpZ2g9IiNEQzFDMTMiKSArdGhlbWUoYXhpcy50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTgpKSArIHNjYWxlX3hfZGlzY3JldGUobGFiZWwgPSBmdW5jdGlvbih4KSBzdHJpbmdyOjpzdHJfd3JhcChnc3ViKCJfIiwgIiAiLHgpLCB3aWR0aCA9IDMwKSkgKyBsYWJzKHRpdGxlID0gIkNvbW1vbiBQVk1MX3ZzX05BV00gJiBQVk1MX3ZzX1dNTCAmIFdNTF92c19DTCIpICsgeGxhYigiIikgKyBjb29yZF9mbGlwKCkgKyB0aGVtZV9idygpKyB0aGVtZShheGlzLnRleHQgPSBlbGVtZW50X3RleHQoZmFjZT0iYm9sZCIpKQpgYGAKCiMjIyBDb21tb24gUFZNTF92c19OQVdNICYgV01MX3ZzX0NMCmBgYHtyIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcGFnZWQucHJpbnQ9VFJVRSwgZmlnLndpZHRoID0gMTAsIGZpZy5oZWlnaHQgPSA4fQpnZ3Bsb3QoZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5XTUxfdnNfQ0wsIGFlcyh4PXJlb3JkZXIocm93bmFtZXMoZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5XTUxfdnNfQ0wpLC1yYW5rKE5PTV9wdmFsKSksIHk9LWxvZzEwKE5PTV9wdmFsKSxmaWxsPS1sb2cxMChOT01fcHZhbCkpKSArIGdlb21fY29sKHdpZHRoPS42NSkrIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93PSIjRjZCREMwIixoaWdoPSIjREMxQzEzIikgK3RoZW1lKGF4aXMudGV4dD1lbGVtZW50X3RleHQoc2l6ZT04KSkgKyBzY2FsZV94X2Rpc2NyZXRlKGxhYmVsID0gZnVuY3Rpb24oeCkgc3RyaW5ncjo6c3RyX3dyYXAoZ3N1YigiXyIsICIgIix4KSwgd2lkdGggPSAzMCkpICsgbGFicyh0aXRsZSA9ICJDb21tb24gUFZNTF92c19OQVdNICYgV01MX3ZzX0NMIikgKyB4bGFiKCIiKSArIGNvb3JkX2ZsaXAoKSArIHRoZW1lX2J3KCkrIHRoZW1lKGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChmYWNlPSJib2xkIikpCmBgYAoKIyMgVHJhbnNjcmlwdGlvbiBmYWN0b3IgdGFyZ2V0cyB7LnRhYnNldH0KYGBge3IgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBwYWdlZC5wcmludD1UUlVFLCBmaWcud2lkdGggPSAxMCwgZmlnLmhlaWdodCA9IDh9CiAgZW5yLnNwZWNpZmljV01MX3ZzX0NMID0gZmlzaFRGVCRzcGVjaWZpY1dNTF92c19DTAogIGVuci5zcGVjaWZpY1dNTF92c19DTCRwYXRod2F5ID0gcm93bmFtZXMoZW5yLnNwZWNpZmljV01MX3ZzX0NMKQogIGVuci5zcGVjaWZpY1dNTF92c19DTCRmZHIgPC0gYXMubnVtZXJpYyhlbnIuc3BlY2lmaWNXTUxfdnNfQ0wkZmRyKSAKICBlbnIuc3BlY2lmaWNXTUxfdnNfQ0wkT1Iub2Rkcy5yYXRpbyA8LSBhcy5udW1lcmljKGVuci5zcGVjaWZpY1dNTF92c19DTCRPUi5vZGRzLnJhdGlvKSAKICBlbnIuc3BlY2lmaWNXTUxfdnNfQ0wkTk9NX3B2YWwgPC0gYXMubnVtZXJpYyhlbnIuc3BlY2lmaWNXTUxfdnNfQ0wkTk9NX3B2YWwpCiAgdG9wc3BlY2lmaWNXTUxfdnNfQ0wgPC0gdG9wUGF0aChmaXNoVEZUICwic3BlY2lmaWNXTUxfdnNfQ0wiLCAwLjUsIDIwKQogIGVuci5zcGVjaWZpY1dNTF92c19DTCA8LSBlbnIuc3BlY2lmaWNXTUxfdnNfQ0xbbWF0Y2godG9wc3BlY2lmaWNXTUxfdnNfQ0wsIHJvd25hbWVzKGVuci5zcGVjaWZpY1dNTF92c19DTCkpLF0KICBlbnIuc3BlY2lmaWNXTUxfdnNfQ0w9ZW5yLnNwZWNpZmljV01MX3ZzX0NMW29yZGVyKGVuci5zcGVjaWZpY1dNTF92c19DTCROT01fcHZhbCksXQogIGVuci5zcGVjaWZpY1dNTF92c19DTCRjb21wID0gInNwZWNpZmljV01MX3ZzX0NMIgogIAogIGVuci5zcGVjaWZpY1BWTUxfdnNfTkFXTSA9IGZpc2hURlQkc3BlY2lmaWNQVk1MX3ZzX05BV00KICBlbnIuc3BlY2lmaWNQVk1MX3ZzX05BV00kcGF0aHdheSA9IHJvd25hbWVzKGVuci5zcGVjaWZpY1BWTUxfdnNfTkFXTSkKICBlbnIuc3BlY2lmaWNQVk1MX3ZzX05BV00kZmRyIDwtIGFzLm51bWVyaWMoZW5yLnNwZWNpZmljUFZNTF92c19OQVdNJGZkcikgCiAgZW5yLnNwZWNpZmljUFZNTF92c19OQVdNJE9SLm9kZHMucmF0aW8gPC0gYXMubnVtZXJpYyhlbnIuc3BlY2lmaWNQVk1MX3ZzX05BV00kT1Iub2Rkcy5yYXRpbykgCiAgZW5yLnNwZWNpZmljUFZNTF92c19OQVdNJE5PTV9wdmFsIDwtIGFzLm51bWVyaWMoZW5yLnNwZWNpZmljUFZNTF92c19OQVdNJE5PTV9wdmFsKQogIHRvcHNwZWNpZmljUFZNTF92c19OQVdNIDwtIHRvcFBhdGgoZmlzaFRGVCAsInNwZWNpZmljUFZNTF92c19OQVdNIiwgMC41LCAyMCkKICBlbnIuc3BlY2lmaWNQVk1MX3ZzX05BV00gPC0gZW5yLnNwZWNpZmljUFZNTF92c19OQVdNW21hdGNoKHRvcHNwZWNpZmljUFZNTF92c19OQVdNLCByb3duYW1lcyhlbnIuc3BlY2lmaWNQVk1MX3ZzX05BV00pKSxdCiAgZW5yLnNwZWNpZmljUFZNTF92c19OQVdNPWVuci5zcGVjaWZpY1BWTUxfdnNfTkFXTVtvcmRlcihlbnIuc3BlY2lmaWNQVk1MX3ZzX05BV00kTk9NX3B2YWwpLF0KICBlbnIuc3BlY2lmaWNQVk1MX3ZzX05BV00kY29tcCA9ICJzcGVjaWZpY1BWTUxfdnNfTkFXTSIKICAKICBlbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MID0gZmlzaFRGVCRjb21tb25QVk1MX3ZzX05BV00uUFZNTF92c19XTUwKICBlbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MJHBhdGh3YXkgPSByb3duYW1lcyhlbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MKQogIGVuci5jb21tb25QVk1MX3ZzX05BV00uUFZNTF92c19XTUwkZmRyIDwtIGFzLm51bWVyaWMoZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTCRmZHIpIAogIGVuci5jb21tb25QVk1MX3ZzX05BV00uUFZNTF92c19XTUwkT1Iub2Rkcy5yYXRpbyA8LSBhcy5udW1lcmljKGVuci5jb21tb25QVk1MX3ZzX05BV00uUFZNTF92c19XTUwkT1Iub2Rkcy5yYXRpbykgCiAgZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTCROT01fcHZhbCA8LSBhcy5udW1lcmljKGVuci5jb21tb25QVk1MX3ZzX05BV00uUFZNTF92c19XTUwkTk9NX3B2YWwpCiAgdG9wY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MIDwtIHRvcFBhdGgoZmlzaFRGVCAsImNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTCIsIDAuNSwgMjApCiAgZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTCA8LSBlbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MW21hdGNoKHRvcGNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTCwgcm93bmFtZXMoZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTCkpLF0KICBlbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MPWVuci5jb21tb25QVk1MX3ZzX05BV00uUFZNTF92c19XTUxbb3JkZXIoZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTCROT01fcHZhbCksXQogIGVuci5jb21tb25QVk1MX3ZzX05BV00uUFZNTF92c19XTUwkY29tcCA9ICJjb21tb25QVk1MX3ZzX05BV00gJiBQVk1MX3ZzX1dNTCIKICAKICBlbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MLldNTF92c19DTCA9IGZpc2hURlQkY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MLldNTF92c19DTAogIGVuci5jb21tb25QVk1MX3ZzX05BV00uUFZNTF92c19XTUwuV01MX3ZzX0NMJHBhdGh3YXkgPSByb3duYW1lcyhlbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MLldNTF92c19DTCkKICBlbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MLldNTF92c19DTCRmZHIgPC0gYXMubnVtZXJpYyhlbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MLldNTF92c19DTCRmZHIpIAogIGVuci5jb21tb25QVk1MX3ZzX05BV00uUFZNTF92c19XTUwuV01MX3ZzX0NMJE9SLm9kZHMucmF0aW8gPC0gYXMubnVtZXJpYyhlbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MLldNTF92c19DTCRPUi5vZGRzLnJhdGlvKSAKICBlbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MLldNTF92c19DTCROT01fcHZhbCA8LSBhcy5udW1lcmljKGVuci5jb21tb25QVk1MX3ZzX05BV00uUFZNTF92c19XTUwuV01MX3ZzX0NMJE5PTV9wdmFsKQogIHRvcGNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTC5XTUxfdnNfQ0wgPC0gdG9wUGF0aChmaXNoVEZUICwiY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MLldNTF92c19DTCIsIDAuNSwyMCkKICBlbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MLldNTF92c19DTCA8LSBlbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MLldNTF92c19DTFttYXRjaCh0b3Bjb21tb25QVk1MX3ZzX05BV00uUFZNTF92c19XTUwuV01MX3ZzX0NMLCByb3duYW1lcyhlbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MLldNTF92c19DTCkpLF0KICBlbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MLldNTF92c19DTD1lbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MLldNTF92c19DTFtvcmRlcihlbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MLldNTF92c19DTCROT01fcHZhbCksXQogIGVuci5jb21tb25QVk1MX3ZzX05BV00uUFZNTF92c19XTUwuV01MX3ZzX0NMJGNvbXAgPSAiY29tbW9uUFZNTF92c19OQVdNICYgUFZNTF92c19XTUwgJiBXTUxfdnNfQ0wiCgogIGVuci5jb21tb25QVk1MX3ZzX05BV00uV01MX3ZzX0NMID0gZmlzaFRGVCRjb21tb25QVk1MX3ZzX05BV00uV01MX3ZzX0NMCiAgZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5XTUxfdnNfQ0wkcGF0aHdheSA9IHJvd25hbWVzKGVuci5jb21tb25QVk1MX3ZzX05BV00uV01MX3ZzX0NMKQogIGVuci5jb21tb25QVk1MX3ZzX05BV00uV01MX3ZzX0NMJGZkciA8LSBhcy5udW1lcmljKGVuci5jb21tb25QVk1MX3ZzX05BV00uV01MX3ZzX0NMJGZkcikgCiAgZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5XTUxfdnNfQ0wkT1Iub2Rkcy5yYXRpbyA8LSBhcy5udW1lcmljKGVuci5jb21tb25QVk1MX3ZzX05BV00uV01MX3ZzX0NMJE9SLm9kZHMucmF0aW8pIAogIGVuci5jb21tb25QVk1MX3ZzX05BV00uV01MX3ZzX0NMJE5PTV9wdmFsIDwtIGFzLm51bWVyaWMoZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5XTUxfdnNfQ0wkTk9NX3B2YWwpCiAgdG9wY29tbW9uUFZNTF92c19OQVdNLldNTF92c19DTCA8LSB0b3BQYXRoKGZpc2hURlQgLCJjb21tb25QVk1MX3ZzX05BV00uV01MX3ZzX0NMIiwgMC41LDIwKQogIGVuci5jb21tb25QVk1MX3ZzX05BV00uV01MX3ZzX0NMIDwtIGVuci5jb21tb25QVk1MX3ZzX05BV00uV01MX3ZzX0NMW21hdGNoKHRvcGNvbW1vblBWTUxfdnNfTkFXTS5XTUxfdnNfQ0wsIHJvd25hbWVzKGVuci5jb21tb25QVk1MX3ZzX05BV00uV01MX3ZzX0NMKSksXQogIGVuci5jb21tb25QVk1MX3ZzX05BV00uV01MX3ZzX0NMPWVuci5jb21tb25QVk1MX3ZzX05BV00uV01MX3ZzX0NMW29yZGVyKGVuci5jb21tb25QVk1MX3ZzX05BV00uV01MX3ZzX0NMJE5PTV9wdmFsKSxdCiAgZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5XTUxfdnNfQ0wkY29tcCA9ICJjb21tb25QVk1MX3ZzX05BV00gJiBQVk1MX3ZzX1dNTCIgIAoKYGBgCgoKIyMjIFNwZWNpZmljIFdNTF92c19DTApgYGB7ciBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIHBhZ2VkLnByaW50PVRSVUUsIGZpZy53aWR0aCA9IDEwLCBmaWcuaGVpZ2h0ID0gOH0KZ2dwbG90KGVuci5zcGVjaWZpY1dNTF92c19DTCwgYWVzKHg9cmVvcmRlcihyb3duYW1lcyhlbnIuc3BlY2lmaWNXTUxfdnNfQ0wpLC1yYW5rKE5PTV9wdmFsKSksIHk9LWxvZzEwKE5PTV9wdmFsKSxmaWxsPS1sb2cxMChOT01fcHZhbCkpKSArIGdlb21fY29sKHdpZHRoPS42NSkrIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93PSIjRjZCREMwIixoaWdoPSIjREMxQzEzIikgK3RoZW1lKGF4aXMudGV4dD1lbGVtZW50X3RleHQoc2l6ZT04KSkgKyBzY2FsZV94X2Rpc2NyZXRlKGxhYmVsID0gZnVuY3Rpb24oeCkgc3RyaW5ncjo6c3RyX3dyYXAoZ3N1YigiXyIsICIgIix4KSwgd2lkdGggPSAzMCkpICsgbGFicyh0aXRsZSA9ICJXTUxfdnNfQ0wiKSArIHhsYWIoIiIpICsgY29vcmRfZmxpcCgpICsgdGhlbWVfYncoKQpgYGAKCiMjIyBTcGVjaWZpYyBQVk1MX3ZzX05BV00KYGBge3IgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBwYWdlZC5wcmludD1UUlVFLCBmaWcud2lkdGggPSAxMCwgZmlnLmhlaWdodCA9IDh9CmdncGxvdChlbnIuc3BlY2lmaWNQVk1MX3ZzX05BV00sIGFlcyh4PXJlb3JkZXIocm93bmFtZXMoZW5yLnNwZWNpZmljUFZNTF92c19OQVdNKSwtcmFuayhOT01fcHZhbCkpLCB5PS1sb2cxMChOT01fcHZhbCksZmlsbD0tbG9nMTAoTk9NX3B2YWwpKSkgKyBnZW9tX2NvbCh3aWR0aD0uNjUpKyBzY2FsZV9maWxsX2dyYWRpZW50KGxvdz0iI0Y2QkRDMCIsaGlnaD0iI0RDMUMxMyIpICt0aGVtZShheGlzLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9OCkpICsgc2NhbGVfeF9kaXNjcmV0ZShsYWJlbCA9IGZ1bmN0aW9uKHgpIHN0cmluZ3I6OnN0cl93cmFwKGdzdWIoIl8iLCAiICIseCksIHdpZHRoID0gMzApKSArIGxhYnModGl0bGUgPSAiUFZNTF92c19OQVdNIikgKyB4bGFiKCIiKSArIGNvb3JkX2ZsaXAoKSArIHRoZW1lX2J3KCkKYGBgCgojIyMgQ29tbW9uIFBWTUxfdnNfTkFXTSAmIFBWTUxfdnNfV01MCmBgYHtyIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcGFnZWQucHJpbnQ9VFJVRSwgZmlnLndpZHRoID0gMTAsIGZpZy5oZWlnaHQgPSA4fQpnZ3Bsb3QoZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTCwgYWVzKHg9cmVvcmRlcihyb3duYW1lcyhlbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MKSwtcmFuayhOT01fcHZhbCkpLCB5PS1sb2cxMChOT01fcHZhbCksZmlsbD0tbG9nMTAoTk9NX3B2YWwpKSkgKyBnZW9tX2NvbCh3aWR0aD0uNjUpKyBzY2FsZV9maWxsX2dyYWRpZW50KGxvdz0iI0Y2QkRDMCIsaGlnaD0iI0RDMUMxMyIpICt0aGVtZShheGlzLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9OCkpICsgc2NhbGVfeF9kaXNjcmV0ZShsYWJlbCA9IGZ1bmN0aW9uKHgpIHN0cmluZ3I6OnN0cl93cmFwKGdzdWIoIl8iLCAiICIseCksIHdpZHRoID0gMzApKSArIGxhYnModGl0bGUgPSAiY29tbW9uIFBWTUxfdnNfTkFXTSAmIFBWTUxfdnNfV01MIikgKyB4bGFiKCIiKSArIGNvb3JkX2ZsaXAoKSArIHRoZW1lX2J3KCkKYGBgCgojIyMgQ29tbW9uIFBWTUxfdnNfTkFXTSAmIFBWTUxfdnNfV01MICYgV01MX3ZzX0NMCmBgYHtyIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcGFnZWQucHJpbnQ9VFJVRSwgZmlnLndpZHRoID0gMTAsIGZpZy5oZWlnaHQgPSA4fQpnZ3Bsb3QoZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTC5XTUxfdnNfQ0wsIGFlcyh4PXJlb3JkZXIocm93bmFtZXMoZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTC5XTUxfdnNfQ0wpLC1yYW5rKE5PTV9wdmFsKSksIHk9LWxvZzEwKE5PTV9wdmFsKSxmaWxsPS1sb2cxMChOT01fcHZhbCkpKSArIGdlb21fY29sKHdpZHRoPS42NSkrIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93PSIjRjZCREMwIixoaWdoPSIjREMxQzEzIikgK3RoZW1lKGF4aXMudGV4dD1lbGVtZW50X3RleHQoc2l6ZT04KSkgKyBzY2FsZV94X2Rpc2NyZXRlKGxhYmVsID0gZnVuY3Rpb24oeCkgc3RyaW5ncjo6c3RyX3dyYXAoZ3N1YigiXyIsICIgIix4KSwgd2lkdGggPSAzMCkpICsgbGFicyh0aXRsZSA9ICJDb21tb24gUFZNTF92c19OQVdNICYgUFZNTF92c19XTUwgJiBXTUxfdnNfQ0wiKSArIHhsYWIoIiIpICsgY29vcmRfZmxpcCgpICsgdGhlbWVfYncoKQpgYGAKCiMjIyBDb21tb24gUFZNTF92c19OQVdNICYgV01MX3ZzX0NMCmBgYHtyIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcGFnZWQucHJpbnQ9VFJVRSwgZmlnLndpZHRoID0gMTAsIGZpZy5oZWlnaHQgPSA4fQpnZ3Bsb3QoZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5XTUxfdnNfQ0wsIGFlcyh4PXJlb3JkZXIocm93bmFtZXMoZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5XTUxfdnNfQ0wpLC1yYW5rKE5PTV9wdmFsKSksIHk9LWxvZzEwKE5PTV9wdmFsKSxmaWxsPS1sb2cxMChOT01fcHZhbCkpKSArIGdlb21fY29sKHdpZHRoPS42NSkrIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93PSIjRjZCREMwIixoaWdoPSIjREMxQzEzIikgK3RoZW1lKGF4aXMudGV4dD1lbGVtZW50X3RleHQoc2l6ZT04KSkgKyBzY2FsZV94X2Rpc2NyZXRlKGxhYmVsID0gZnVuY3Rpb24oeCkgc3RyaW5ncjo6c3RyX3dyYXAoZ3N1YigiXyIsICIgIix4KSwgd2lkdGggPSAzMCkpICsgbGFicyh0aXRsZSA9ICJDb21tb24gUFZNTF92c19OQVdNICYgV01MX3ZzX0NMIikgKyB4bGFiKCIiKSArIGNvb3JkX2ZsaXAoKSArIHRoZW1lX2J3KCkKYGBgCgojIyBLRUdHIHBhdGh3YXkgZGF0YWJhc2Ugey50YWJzZXR9CmBgYHtyIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcGFnZWQucHJpbnQ9VFJVRSwgZmlnLndpZHRoID0gMTAsIGZpZy5oZWlnaHQgPSA4fQogIGVuci5zcGVjaWZpY1dNTF92c19DTCA9IGZpc2hLRUdHJHNwZWNpZmljV01MX3ZzX0NMCiAgZW5yLnNwZWNpZmljV01MX3ZzX0NMJHBhdGh3YXkgPSByb3duYW1lcyhlbnIuc3BlY2lmaWNXTUxfdnNfQ0wpCiAgZW5yLnNwZWNpZmljV01MX3ZzX0NMJGZkciA8LSBhcy5udW1lcmljKGVuci5zcGVjaWZpY1dNTF92c19DTCRmZHIpIAogIGVuci5zcGVjaWZpY1dNTF92c19DTCRPUi5vZGRzLnJhdGlvIDwtIGFzLm51bWVyaWMoZW5yLnNwZWNpZmljV01MX3ZzX0NMJE9SLm9kZHMucmF0aW8pIAogIGVuci5zcGVjaWZpY1dNTF92c19DTCROT01fcHZhbCA8LSBhcy5udW1lcmljKGVuci5zcGVjaWZpY1dNTF92c19DTCROT01fcHZhbCkKICB0b3BzcGVjaWZpY1dNTF92c19DTCA8LSB0b3BQYXRoKGZpc2hLRUdHICwic3BlY2lmaWNXTUxfdnNfQ0wiLCAwLjUsIDIwKQogIGVuci5zcGVjaWZpY1dNTF92c19DTCA8LSBlbnIuc3BlY2lmaWNXTUxfdnNfQ0xbbWF0Y2godG9wc3BlY2lmaWNXTUxfdnNfQ0wsIHJvd25hbWVzKGVuci5zcGVjaWZpY1dNTF92c19DTCkpLF0KICByb3duYW1lcyhlbnIuc3BlY2lmaWNXTUxfdnNfQ0wpIDwtIGdzdWIoIktFR0ciLCAiIixyb3duYW1lcyhlbnIuc3BlY2lmaWNXTUxfdnNfQ0wpKSAKICBlbnIuc3BlY2lmaWNXTUxfdnNfQ0w9ZW5yLnNwZWNpZmljV01MX3ZzX0NMW29yZGVyKGVuci5zcGVjaWZpY1dNTF92c19DTCROT01fcHZhbCksXQogIGVuci5zcGVjaWZpY1dNTF92c19DTCRjb21wID0gInNwZWNpZmljV01MX3ZzX0NMIgogIAogIGVuci5zcGVjaWZpY1BWTUxfdnNfTkFXTSA9IGZpc2hLRUdHJHNwZWNpZmljUFZNTF92c19OQVdNCiAgZW5yLnNwZWNpZmljUFZNTF92c19OQVdNJHBhdGh3YXkgPSByb3duYW1lcyhlbnIuc3BlY2lmaWNQVk1MX3ZzX05BV00pCiAgZW5yLnNwZWNpZmljUFZNTF92c19OQVdNJGZkciA8LSBhcy5udW1lcmljKGVuci5zcGVjaWZpY1BWTUxfdnNfTkFXTSRmZHIpIAogIGVuci5zcGVjaWZpY1BWTUxfdnNfTkFXTSRPUi5vZGRzLnJhdGlvIDwtIGFzLm51bWVyaWMoZW5yLnNwZWNpZmljUFZNTF92c19OQVdNJE9SLm9kZHMucmF0aW8pIAogIGVuci5zcGVjaWZpY1BWTUxfdnNfTkFXTSROT01fcHZhbCA8LSBhcy5udW1lcmljKGVuci5zcGVjaWZpY1BWTUxfdnNfTkFXTSROT01fcHZhbCkKICB0b3BzcGVjaWZpY1BWTUxfdnNfTkFXTSA8LSB0b3BQYXRoKGZpc2hLRUdHICwic3BlY2lmaWNQVk1MX3ZzX05BV00iLCAwLjUsIDIwKQogIGVuci5zcGVjaWZpY1BWTUxfdnNfTkFXTSA8LSBlbnIuc3BlY2lmaWNQVk1MX3ZzX05BV01bbWF0Y2godG9wc3BlY2lmaWNQVk1MX3ZzX05BV00sIHJvd25hbWVzKGVuci5zcGVjaWZpY1BWTUxfdnNfTkFXTSkpLF0KICByb3duYW1lcyhlbnIuc3BlY2lmaWNQVk1MX3ZzX05BV00pIDwtIGdzdWIoIktFR0ciLCAiIixyb3duYW1lcyhlbnIuc3BlY2lmaWNQVk1MX3ZzX05BV00pKSAKICBlbnIuc3BlY2lmaWNQVk1MX3ZzX05BV009ZW5yLnNwZWNpZmljUFZNTF92c19OQVdNW29yZGVyKGVuci5zcGVjaWZpY1BWTUxfdnNfTkFXTSROT01fcHZhbCksXQogIGVuci5zcGVjaWZpY1BWTUxfdnNfTkFXTSRjb21wID0gInNwZWNpZmljUFZNTF92c19OQVdNIgogIAogIGVuci5jb21tb25QVk1MX3ZzX05BV00uUFZNTF92c19XTUwgPSBmaXNoS0VHRyRjb21tb25QVk1MX3ZzX05BV00uUFZNTF92c19XTUwKICBlbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MJHBhdGh3YXkgPSByb3duYW1lcyhlbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MKQogIGVuci5jb21tb25QVk1MX3ZzX05BV00uUFZNTF92c19XTUwkZmRyIDwtIGFzLm51bWVyaWMoZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTCRmZHIpIAogIGVuci5jb21tb25QVk1MX3ZzX05BV00uUFZNTF92c19XTUwkT1Iub2Rkcy5yYXRpbyA8LSBhcy5udW1lcmljKGVuci5jb21tb25QVk1MX3ZzX05BV00uUFZNTF92c19XTUwkT1Iub2Rkcy5yYXRpbykgCiAgZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTCROT01fcHZhbCA8LSBhcy5udW1lcmljKGVuci5jb21tb25QVk1MX3ZzX05BV00uUFZNTF92c19XTUwkTk9NX3B2YWwpCiAgZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTD1lbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MW29yZGVyKGVuci5jb21tb25QVk1MX3ZzX05BV00uUFZNTF92c19XTUwkTk9NX3B2YWwpLF0KICB0b3Bjb21tb25QVk1MX3ZzX05BV00uUFZNTF92c19XTUwgPSBzdWJzZXQoZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTCxOT01fcHZhbDw9MC4xKQogIHRvcGNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTCA9IHRvcGNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTCRwYXRod2F5CiAgZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTCA8LSBlbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MW21hdGNoKHRvcGNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTCwgcm93bmFtZXMoZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTCkpLF0KICByb3duYW1lcyhlbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MKSA8LSBnc3ViKCJLRUdHIiwgIiIscm93bmFtZXMoZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTCkpIAogIGVuci5jb21tb25QVk1MX3ZzX05BV00uUFZNTF92c19XTUw9ZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTFtvcmRlcihlbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MJE5PTV9wdmFsKSxdCiAgZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTCRjb21wID0gImNvbW1vblBWTUxfdnNfTkFXTSAmIFBWTUxfdnNfV01MIgogIAogIGVuci5jb21tb25QVk1MX3ZzX05BV00uUFZNTF92c19XTUwuV01MX3ZzX0NMID0gZmlzaEtFR0ckY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MLldNTF92c19DTAogIGVuci5jb21tb25QVk1MX3ZzX05BV00uUFZNTF92c19XTUwuV01MX3ZzX0NMJHBhdGh3YXkgPSByb3duYW1lcyhlbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MLldNTF92c19DTCkKICBlbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MLldNTF92c19DTCRmZHIgPC0gYXMubnVtZXJpYyhlbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MLldNTF92c19DTCRmZHIpIAogIGVuci5jb21tb25QVk1MX3ZzX05BV00uUFZNTF92c19XTUwuV01MX3ZzX0NMJE9SLm9kZHMucmF0aW8gPC0gYXMubnVtZXJpYyhlbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MLldNTF92c19DTCRPUi5vZGRzLnJhdGlvKSAKICBlbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MLldNTF92c19DTCROT01fcHZhbCA8LSBhcy5udW1lcmljKGVuci5jb21tb25QVk1MX3ZzX05BV00uUFZNTF92c19XTUwuV01MX3ZzX0NMJE5PTV9wdmFsKQogIHRvcGNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTC5XTUxfdnNfQ0wgPC0gdG9wUGF0aChmaXNoS0VHRyAsImNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTC5XTUxfdnNfQ0wiLCAwLjUsMjApCiAgZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTC5XTUxfdnNfQ0wgPC0gZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTC5XTUxfdnNfQ0xbbWF0Y2godG9wY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MLldNTF92c19DTCwgcm93bmFtZXMoZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTC5XTUxfdnNfQ0wpKSxdCiAgcm93bmFtZXMoZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTC5XTUxfdnNfQ0wpIDwtIGdzdWIoIktFR0ciLCAiIixyb3duYW1lcyhlbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MLldNTF92c19DTCkpIAogIGVuci5jb21tb25QVk1MX3ZzX05BV00uUFZNTF92c19XTUwuV01MX3ZzX0NMPWVuci5jb21tb25QVk1MX3ZzX05BV00uUFZNTF92c19XTUwuV01MX3ZzX0NMW29yZGVyKGVuci5jb21tb25QVk1MX3ZzX05BV00uUFZNTF92c19XTUwuV01MX3ZzX0NMJE5PTV9wdmFsKSxdCiAgZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5QVk1MX3ZzX1dNTC5XTUxfdnNfQ0wkY29tcCA9ICJjb21tb25QVk1MX3ZzX05BV00gJiBQVk1MX3ZzX1dNTCAmIFdNTF92c19DTCIKCiAgZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5XTUxfdnNfQ0wgPSBmaXNoS0VHRyRjb21tb25QVk1MX3ZzX05BV00uV01MX3ZzX0NMCiAgZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5XTUxfdnNfQ0wkcGF0aHdheSA9IHJvd25hbWVzKGVuci5jb21tb25QVk1MX3ZzX05BV00uV01MX3ZzX0NMKQogIGVuci5jb21tb25QVk1MX3ZzX05BV00uV01MX3ZzX0NMJGZkciA8LSBhcy5udW1lcmljKGVuci5jb21tb25QVk1MX3ZzX05BV00uV01MX3ZzX0NMJGZkcikgCiAgZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5XTUxfdnNfQ0wkT1Iub2Rkcy5yYXRpbyA8LSBhcy5udW1lcmljKGVuci5jb21tb25QVk1MX3ZzX05BV00uV01MX3ZzX0NMJE9SLm9kZHMucmF0aW8pIAogIGVuci5jb21tb25QVk1MX3ZzX05BV00uV01MX3ZzX0NMJE5PTV9wdmFsIDwtIGFzLm51bWVyaWMoZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5XTUxfdnNfQ0wkTk9NX3B2YWwpCiAgdG9wY29tbW9uUFZNTF92c19OQVdNLldNTF92c19DTCA9IHN1YnNldChlbnIuY29tbW9uUFZNTF92c19OQVdNLldNTF92c19DTCxOT01fcHZhbDw9MC4xKQogIHRvcGNvbW1vblBWTUxfdnNfTkFXTS5XTUxfdnNfQ0wgPSB0b3Bjb21tb25QVk1MX3ZzX05BV00uV01MX3ZzX0NMJHBhdGh3YXkKICBlbnIuY29tbW9uUFZNTF92c19OQVdNLldNTF92c19DTCA8LSBlbnIuY29tbW9uUFZNTF92c19OQVdNLldNTF92c19DTFttYXRjaCh0b3Bjb21tb25QVk1MX3ZzX05BV00uV01MX3ZzX0NMLCByb3duYW1lcyhlbnIuY29tbW9uUFZNTF92c19OQVdNLldNTF92c19DTCkpLF0KICByb3duYW1lcyhlbnIuY29tbW9uUFZNTF92c19OQVdNLldNTF92c19DTCkgPC0gZ3N1YigiS0VHRyIsICIiLHJvd25hbWVzKGVuci5jb21tb25QVk1MX3ZzX05BV00uV01MX3ZzX0NMKSkgCiAgZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5XTUxfdnNfQ0w9ZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5XTUxfdnNfQ0xbb3JkZXIoZW5yLmNvbW1vblBWTUxfdnNfTkFXTS5XTUxfdnNfQ0wkTk9NX3B2YWwpLF0KICBlbnIuY29tbW9uUFZNTF92c19OQVdNLldNTF92c19DTCRjb21wID0gImNvbW1vblBWTUxfdnNfTkFXTSAmIFBWTUxfdnNfV01MIiAgCgpgYGAKCgojIyMgU3BlY2lmaWMgV01MX3ZzX0NMCmBgYHtyIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcGFnZWQucHJpbnQ9VFJVRSwgZmlnLndpZHRoID0gMTAsIGZpZy5oZWlnaHQgPSA4fQpnZ3Bsb3QoZW5yLnNwZWNpZmljV01MX3ZzX0NMLCBhZXMoeD1yZW9yZGVyKHJvd25hbWVzKGVuci5zcGVjaWZpY1dNTF92c19DTCksLXJhbmsoTk9NX3B2YWwpKSwgeT0tbG9nMTAoTk9NX3B2YWwpLGZpbGw9LWxvZzEwKE5PTV9wdmFsKSkpICsgZ2VvbV9jb2wod2lkdGg9LjY1KSsgc2NhbGVfZmlsbF9ncmFkaWVudChsb3c9IiNGNkJEQzAiLGhpZ2g9IiNEQzFDMTMiKSArdGhlbWUoYXhpcy50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTgpKSArIHNjYWxlX3hfZGlzY3JldGUobGFiZWwgPSBmdW5jdGlvbih4KSBzdHJpbmdyOjpzdHJfd3JhcChnc3ViKCJfIiwgIiAiLHgpLCB3aWR0aCA9IDMwKSkgKyBsYWJzKHRpdGxlID0gIldNTF92c19DTCIpICsgeGxhYigiIikgKyBjb29yZF9mbGlwKCkgKyB0aGVtZV9idygpCmBgYAoKIyMjIFNwZWNpZmljIFBWTUxfdnNfTkFXTQpgYGB7ciBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIHBhZ2VkLnByaW50PVRSVUUsIGZpZy53aWR0aCA9IDEwLCBmaWcuaGVpZ2h0ID0gOH0KZ2dwbG90KGVuci5zcGVjaWZpY1BWTUxfdnNfTkFXTSwgYWVzKHg9cmVvcmRlcihyb3duYW1lcyhlbnIuc3BlY2lmaWNQVk1MX3ZzX05BV00pLC1yYW5rKE5PTV9wdmFsKSksIHk9LWxvZzEwKE5PTV9wdmFsKSxmaWxsPS1sb2cxMChOT01fcHZhbCkpKSArIGdlb21fY29sKHdpZHRoPS42NSkrIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93PSIjRjZCREMwIixoaWdoPSIjREMxQzEzIikgK3RoZW1lKGF4aXMudGV4dD1lbGVtZW50X3RleHQoc2l6ZT04KSkgKyBzY2FsZV94X2Rpc2NyZXRlKGxhYmVsID0gZnVuY3Rpb24oeCkgc3RyaW5ncjo6c3RyX3dyYXAoZ3N1YigiXyIsICIgIix4KSwgd2lkdGggPSAzMCkpICsgbGFicyh0aXRsZSA9ICJQVk1MX3ZzX05BV00iKSArIHhsYWIoIiIpICsgY29vcmRfZmxpcCgpICsgdGhlbWVfYncoKQpgYGAKCiMjIyBDb21tb24gUFZNTF92c19OQVdNICYgUFZNTF92c19XTUwKYGBge3IgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBwYWdlZC5wcmludD1UUlVFLCBmaWcud2lkdGggPSAxMCwgZmlnLmhlaWdodCA9IDh9CmdncGxvdChlbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MLCBhZXMoeD1yZW9yZGVyKHJvd25hbWVzKGVuci5jb21tb25QVk1MX3ZzX05BV00uUFZNTF92c19XTUwpLC1yYW5rKE5PTV9wdmFsKSksIHk9LWxvZzEwKE5PTV9wdmFsKSxmaWxsPS1sb2cxMChOT01fcHZhbCkpKSArIGdlb21fY29sKHdpZHRoPS42NSkrIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93PSIjRjZCREMwIixoaWdoPSIjREMxQzEzIikgK3RoZW1lKGF4aXMudGV4dD1lbGVtZW50X3RleHQoc2l6ZT04KSkgKyBzY2FsZV94X2Rpc2NyZXRlKGxhYmVsID0gZnVuY3Rpb24oeCkgc3RyaW5ncjo6c3RyX3dyYXAoZ3N1YigiXyIsICIgIix4KSwgd2lkdGggPSAzMCkpICsgbGFicyh0aXRsZSA9ICJjb21tb24gUFZNTF92c19OQVdNICYgUFZNTF92c19XTUwiKSArIHhsYWIoIiIpICsgY29vcmRfZmxpcCgpICsgdGhlbWVfYncoKQpgYGAKCiMjIyBDb21tb24gUFZNTF92c19OQVdNICYgUFZNTF92c19XTUwgJiBXTUxfdnNfQ0wKYGBge3IgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBwYWdlZC5wcmludD1UUlVFLCBmaWcud2lkdGggPSAxMCwgZmlnLmhlaWdodCA9IDh9CmdncGxvdChlbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MLldNTF92c19DTCwgYWVzKHg9cmVvcmRlcihyb3duYW1lcyhlbnIuY29tbW9uUFZNTF92c19OQVdNLlBWTUxfdnNfV01MLldNTF92c19DTCksLXJhbmsoTk9NX3B2YWwpKSwgeT0tbG9nMTAoTk9NX3B2YWwpLGZpbGw9LWxvZzEwKE5PTV9wdmFsKSkpICsgZ2VvbV9jb2wod2lkdGg9LjY1KSsgc2NhbGVfZmlsbF9ncmFkaWVudChsb3c9IiNGNkJEQzAiLGhpZ2g9IiNEQzFDMTMiKSArdGhlbWUoYXhpcy50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTgpKSArIHNjYWxlX3hfZGlzY3JldGUobGFiZWwgPSBmdW5jdGlvbih4KSBzdHJpbmdyOjpzdHJfd3JhcChnc3ViKCJfIiwgIiAiLHgpLCB3aWR0aCA9IDMwKSkgKyBsYWJzKHRpdGxlID0gIkNvbW1vbiBQVk1MX3ZzX05BV00gJiBQVk1MX3ZzX1dNTCAmIFdNTF92c19DTCIpICsgeGxhYigiIikgKyBjb29yZF9mbGlwKCkgKyB0aGVtZV9idygpCmBgYAoKIyMjIGNvbW1vbiBQVk1MX3ZzX05BV00gJiBXTUxfdnNfQ0wKYGBge3IgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBwYWdlZC5wcmludD1UUlVFLCBmaWcud2lkdGggPSAxMCwgZmlnLmhlaWdodCA9IDh9CmdncGxvdChlbnIuY29tbW9uUFZNTF92c19OQVdNLldNTF92c19DTCwgYWVzKHg9cmVvcmRlcihyb3duYW1lcyhlbnIuY29tbW9uUFZNTF92c19OQVdNLldNTF92c19DTCksLXJhbmsoTk9NX3B2YWwpKSwgeT0tbG9nMTAoTk9NX3B2YWwpLGZpbGw9LWxvZzEwKE5PTV9wdmFsKSkpICsgZ2VvbV9jb2wod2lkdGg9LjY1KSsgc2NhbGVfZmlsbF9ncmFkaWVudChsb3c9IiNGNkJEQzAiLGhpZ2g9IiNEQzFDMTMiKSArdGhlbWUoYXhpcy50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTgpKSArIHNjYWxlX3hfZGlzY3JldGUobGFiZWwgPSBmdW5jdGlvbih4KSBzdHJpbmdyOjpzdHJfd3JhcChnc3ViKCJfIiwgIiAiLHgpLCB3aWR0aCA9IDMwKSkgKyBsYWJzKHRpdGxlID0gIkNvbW1vbiBQVk1MX3ZzX05BV00gJiBXTUxfdnNfQ0wiKSArIHhsYWIoIiIpICsgY29vcmRfZmxpcCgpICsgdGhlbWVfYncoKQpgYGAKCgojIFRoaXMgaXMgYW4gYW5hbHlzaXMgcGVyZm9ybWVkIG9uIHRoZSBidWxrIFJOQS1TZXEgZGF0YXNldCBmcm9tIHRoZSBwYXBlciB0aXRsZWQ6ICAgCioqQnJhaW4gbWFjcm9waGFnZXMgYWNxdWlyZSBkaXN0aW5jdCB0cmFuc2NyaXB0b21lcyBpbiBtdWx0aXBsZSBzY2xlcm9zaXMgbGVzaW9ucyBhbmQgbm9ybWFsIGFwcGVhcmluZyB3aGl0ZSBtYXR0ZXIqKi4gIAoKVGhlIGF1dGhvcnMgb2YgdGhpcyBwYXBlciBoYXZlIHNlcXVlbmNlZCA2OCBzYW1wbGVzIG9mIGh1bWFuIGJyYWluIG1hdGVyaWFsLgpIZXJlIGlzIHRoZSBbcGFwZXJdKGh0dHBzOi8vd3d3LmJpb3J4aXYub3JnL2NvbnRlbnQvMTAuMTEwMS8yMDIxLjEwLjI3LjQ2NTg3N3YxLmZ1bGwpCgoqQWJzdHJhY3QqCgpNdWx0aXBsZSBzY2xlcm9zaXMgKE1TKSBpcyBhIGRpc2Vhc2Ugb2YgdGhlIGNlbnRyYWwgbmVydm91cyBzeXN0ZW0gKENOUykgdGhhdCBpcyBjaGFyYWN0ZXJpemVkIGJ5IGluZmxhbW1hdGlvbiBhbmQgZm9jYWwgYXJlYXMgb2YgZGVteWVsaW5hdGlvbiwgdWx0aW1hdGVseSByZXN1bHRpbmcgaW4gYXhvbmFsIGRlZ3JhZGF0aW9uIGFuZCBuZXVyb25hbCBsb3NzLiBTZXZlcmFsIGxpbmVzIG9mIGV2aWRlbmNlIHBvaW50IHRvd2FyZHMgYSByb2xlIGZvciBtaWNyb2dsaWEgYW5kIG90aGVyIGJyYWluIG1hY3JvcGhhZ2VzIGluIGRpc2Vhc2UgaW5pdGlhdGlvbiBhbmQgcHJvZ3Jlc3Npb24sIGJ1dCBleGFjdGx5IGhvdyBsZXNpb24gZm9ybWF0aW9uIGlzIHRyaWdnZXJlZCBpcyBjdXJyZW50bHkgdW5rbm93bi4gSGVyZSwgd2UgY2hhcmFjdGVyaXplZCBlYXJseSBjaGFuZ2VzIGluIE1TIGJyYWluIHRpc3N1ZSB0aHJvdWdoIHRyYW5zY3JpcHRvbWljIGFuYWx5c2lzIG9mIG5vcm1hbCBhcHBlYXJpbmcgd2hpdGUgbWF0dGVyIChOQVdNKS4gV2UgZm91bmQgdGhhdCBOQVdNIHdhcyBjaGFyYWN0ZXJpemVkIGJ5IGVucmljaGVkIGV4cHJlc3Npb24gb2YgZ2VuZXMgYXNzb2NpYXRlZCB3aXRoIGluZmxhbW1hdGlvbiBhbmQgY2VsbHVsYXIgc3RyZXNzIGRlcml2ZWQgZnJvbSBicmFpbiBtYWNyb3BoYWdlcy4gU2luZ2xlIGNlbGwgUk5BIHNlcXVlbmNpbmcgY29uZmlybWVkIGFuIGVhcmx5IHN0cmVzcyByZXNwb25zZSBpbiBicmFpbiBtYWNyb3BoYWdlcyBpbiBOQVdNIGFuZCBpZGVudGlmaWVkIHNwZWNpZmljIG1hY3JvcGhhZ2Ugc3Vic2V0cyB0aGF0IGFzc29jaWF0ZSB3aXRoIGRpZmZlcmVudCBzdGFnZXMgb2YgZGVteWVsaW5hdGluZyBsZXNpb25zLiBUaGVzZSBlYXJseSBjaGFuZ2VzIGFzc29jaWF0ZWQgd2l0aCBsZXNpb24gZGV2ZWxvcG1lbnQgaW4gTVMgYnJhaW4gdGlzc3VlIG1heSBwcm92aWRlIHRoZXJhcGV1dGljIHRhcmdldHMgdG8gbGltaXQgbGVzaW9uIHByb2dyZXNzaW9uIGFuZCBkZW15ZWxpbmF0aW9uLgoKCmBgYHtyIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcGFnZWQucHJpbnQ9VFJVRX0KZ29CUCA9IHJlYWQuZ210KCcvVXNlcnMvbWFjYm9va3Byby9PbmVEcml2ZS9Eb2N1bWVudHMvVURFTS9NYXN0ZXIvQnVsa0RhdGEvR08vYzUuZ28uYnAudjcuNS4xLnN5bWJvbHMuZ210JykKbWV0YVAgPC0gcmVhZC50YWJsZSgiL1VzZXJzL21hY2Jvb2twcm8vT25lRHJpdmUvRG9jdW1lbnRzL1VERU0vTWFzdGVyL0dTRTE3OTQyNy9TcmFSdW5UYWJsZS50eHQiLCBoZWFkZXIgPSBUUlVFLCBzZXAgPSAiLCIpCm1ldGFQIDwtIGRhdGEuZnJhbWUoc2FtcGxlID0gbWV0YVAkU2FtcGxlLk5hbWUsIGdyb3VwPW1ldGFQJEdyb3VwKQptZXRhUCA8LSBtZXRhUFshZHVwbGljYXRlZChtZXRhUFsgLCBjKCJzYW1wbGUiLCAiZ3JvdXAiKV0pLCBdCm1ldGFQJGdyb3VwIDwtIHRvdXBwZXIobWV0YVAkZ3JvdXApCgpyZWZQIDwtIHJlYWQuY3N2KCIvVXNlcnMvbWFjYm9va3Byby9PbmVEcml2ZS9Eb2N1bWVudHMvVURFTS9NYXN0ZXIvR1NFMTc5NDI3L3JlZi5jc3YiLCBoZWFkZXIgPSBUUlVFLCBzZXAgPSAiOyIpCnJlZlAgPC0gZGF0YS5mcmFtZShzYW1wbGUgPSByZWZQJHNhbXBsZSwgc2FtcGxlTmFtZSA9IHJlZlAkc2FtcGxlTmFtZSkKcmVmUCA8LSBtZXJnZShtZXRhUCxyZWZQLGJ5PSJzYW1wbGUiKQoKY291bnRzUCA8LSByZWFkLnRhYmxlKCIvVXNlcnMvbWFjYm9va3Byby9PbmVEcml2ZS9Eb2N1bWVudHMvVURFTS9NYXN0ZXIvR1NFMTc5NDI3L0dTRTE3OTQyN19jb3VudG10eC5jc3YiLCBoZWFkZXIgPSBUUlVFLCBzZXAgPSAiOyIscm93Lm5hbWVzPTEpCmNvdW50c1BbaXMubmEoY291bnRzUCldIDwtIDAKcmVmUFAgPC0gZGF0YS5mcmFtZShzYW1wbGVOYW1lID0gY29sbmFtZXMoY291bnRzUCkpIApyZWZQUCA8LSBtZXJnZShyZWZQUCwgcmVmUCwgYnk9InNhbXBsZU5hbWUiKQoKcmVmUFAkZ3JvdXAgPC0gZ3N1YignTkFHTScsJ05BV00nLHJlZlBQJGdyb3VwKQoKY29uX2NvbG9yc1AgPSBjKCdvbGl2ZWRyYWIyJywnZGVlcHNreWJsdWUnLCdkYXJrb3JhbmdlJykKbmFtZXMoY29uX2NvbG9yc1ApPWMoJ0NPTlRST0wnLCdOQVdNJywnTEVTSU9OJykKCiMjcmVtb3ZlIG1pdG9jaG9uZHJpYWwgZ2VuZQpjb252UD1zZWxlY3Qob3JnLkhzLmVnLmRiLGtleXM9cm93bmFtZXMoRVAkRSksa2V5dHlwZT0nRU5TRU1CTCcsY29sdW1ucz1jKCdHRU5FTkFNRScsJ1NZTUJPTCcpKQpyZWZHUD1jb252UFshZHVwbGljYXRlZChjb252UFssMV0pLF0Kcm93bmFtZXMocmVmR1ApPXJlZkdQWywxXQpjPXN1YnNldChjb252UCxncmVwbCgnbWl0b2Nob24nLGNvbnZQWywyXSkpCmNjID0gc3Vic2V0KGMsZ3JlcGwoJ15NVCcsIGNbLDNdKSkKTkdNaXRvID0gY291bnRzUFshcm93bmFtZXMoY291bnRzUCkgJWluJSBjYyRFTlNFTUJMLF0KCgojIyBsaW1tYSBERUEKZDBQIDwtIERHRUxpc3QoTkdNaXRvKQojZDBQIDwtIERHRUxpc3QoY291bnRzUCkgd2l0aCBtaXRvY2hvbmRyaWFsIGdlbmUKZDBQIDwtIGNhbGNOb3JtRmFjdG9ycyhkMFApCmN1dG9mZiA8LSA1CmRyb3BQIDwtIHdoaWNoKGFwcGx5KGNwbShkMFApLCAxLCBtYXgpIDwgY3V0b2ZmKQpkUCA8LSBkMFBbLWRyb3BQLF0gCgoKbWV0YWRhdGFQIDwtIGRhdGEuZnJhbWUoc2FtcGxlTmFtZT1yb3duYW1lcyhkUCRzYW1wbGVzKSkKbWV0YWRhdGFQJGdyb3VwIDwtIE5BCmZvciAoaSBpbiAxOm5yb3cobWV0YWRhdGFQKSkgewogIGZvciAoaiBpbiAxOm5yb3cocmVmUFApKSB7CiAgICBpZihtZXRhZGF0YVAkc2FtcGxlTmFtZVtpXT09cmVmUFAkc2FtcGxlTmFtZVtqXSl7CiAgICAgIG1ldGFkYXRhUCRncm91cFtpXSA9IHJlZlBQJGdyb3VwW2pdCiAgICAgIGJyZWFrCiAgICB9CiAgICAKICB9Cn0Kcm93bmFtZXMobWV0YWRhdGFQKSA8LSBtZXRhZGF0YVAkc2FtcGxlTmFtZQptZXRhZGF0YVAgPC0gc3Vic2V0KG1ldGFkYXRhUCwgc2VsZWN0PS1jKHNhbXBsZU5hbWUpKQoKbW1QIDwtIG1vZGVsLm1hdHJpeCh+MCArIGdyb3VwOmdyb3VwLGRhdGE9bWV0YWRhdGFQKQpFUCA8LSB2b29tKGRQLCBtbVAsIHBsb3QgPSBGKQpgYGAKCiMjIyBQcmluY2lwYWwgY29tcG9uZW50IGFuYWx5c2lzIG9mIDY4IHdoaXRlIG1hdHRlciBicmFpbiB0aXNzdWUgc2FtcGxlcy4KCiMjIyMgMjYgQ29udHJvbAojIyMjIDMxIE5BV00KIyMjIyAxMSBMZXNpb24KCmBgYHtyIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcGFnZWQucHJpbnQ9RkFMU0UsIGZpZy53aWR0aCA9IDQsIGZpZy5oZWlnaHQgPSAzfQpwIDwtIHBjYShFUCRFLCBtZXRhZGF0YSA9IG1ldGFkYXRhUCkKcGxvdDEgPC0gYmlwbG90KHAsIGNvbGJ5ID0gJ2dyb3VwJyxobGluZSA9IDAsIHZsaW5lID0gMCxsZWdlbmRQb3NpdGlvbiA9ICdyaWdodCcsIGxhYj0iIikKcGxvdDI8LSBwbG90MSAgKyAgc2NhbGVfY29sb3JfbWFudWFsKCBuYW1lPSAiR3JvdXBzIixsYWJlbHMgPSBjKCJDT05UUk9MIiwiTEVTSU9OIiwiTkFXTSIpLCB2YWx1ZXM9IGMoJ29saXZlZHJhYjInLCdkYXJrb3JhbmdlNCcsJ2dvbGRlbnJvZDInKSkgCnBsb3QyCmBgYAoKIyMgQ29tcGFyaXNvbnMgYmV0d2VlbiBjb25kaXRpb25zCmBgYHtyIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcGFnZWQucHJpbnQ9RkFMU0V9CmZpdFAgPC0gbG1GaXQoRVAsIG1tUCkKY29udHJQIDwtIG1ha2VDb250cmFzdHMoCiAgICAgICAgICAgICAgQT0gZ3JvdXBOQVdNIC0gZ3JvdXBDT05UUk9MLAogICAgICAgICAgICAgIEI9IGdyb3VwTEVTSU9OIC0gZ3JvdXBOQVdNLAogICAgICAgICAgICAgIEM9IGdyb3VwTEVTSU9OIC0gZ3JvdXBDT05UUk9MLCBsZXZlbHMgPSBjb2xuYW1lcyhjb2VmKGZpdFApKSkKdG1wUCA8LSBjb250cmFzdHMuZml0KGZpdFAsY29udHJQKQp0bXBQIDwtIGVCYXllcyh0bXBQKQoKcmVzLkFQIDwtIHRvcFRhYmxlKHRtcFAsIHNvcnQuYnkgPSAiUCIsIG4gPSBJbmYsIGNvZWY9J0EnLGFkanVzdD0iZmRyIikKcmVzLkJQIDwtIHRvcFRhYmxlKHRtcFAsIHNvcnQuYnkgPSAiUCIsIG4gPSBJbmYsIGNvZWY9J0InLGFkanVzdD0iZmRyIikKcmVzLkNQIDwtIHRvcFRhYmxlKHRtcFAsIHNvcnQuYnkgPSAiUCIsIG4gPSBJbmYsIGNvZWY9J0MnLGFkanVzdD0iZmRyIikKCnJlcy5BUCRjb25kaXRpb24gPSAnQTogTkFXTSB2cyBDV00nCnJlcy5CUCRjb25kaXRpb24gPSAnQjogV01MIHZzIE5BV00nCnJlcy5DUCRjb25kaXRpb24gPSAnQzogV01MIHZzIENXTScKCnJlcy5BUCRnZW5laWQgPSByb3duYW1lcyhyZXMuQVApCnJlcy5CUCRnZW5laWQgPSByb3duYW1lcyhyZXMuQlApCnJlcy5DUCRnZW5laWQgPSByb3duYW1lcyhyZXMuQ1ApCgpyZXMuVCA9IHJiaW5kKHJlcy5BUCxyZXMuQlAscmVzLkNQKQpyZXMuVCRzeW1ib2wgPSByZWZHUFtyZXMuVCRnZW5laWQsM10KcmVzLkFQJHN5bWJvbCA9IHJlZkdQW3Jlcy5BUCRnZW5laWQsM10KcmVzLkJQJHN5bWJvbCA9IHJlZkdQW3Jlcy5CUCRnZW5laWQsM10KcmVzLkNQJHN5bWJvbCA9IHJlZkdQW3Jlcy5DUCRnZW5laWQsM10KCmRlZ3MuQVAgPSBzdWJzZXQocmVzLlQsIGNvbmRpdGlvbiA9PSAnQTogTkFXTSB2cyBDV00nICYgYWRqLlAuVmFsPDAuMDUgJiBhYnMobG9nRkMpPjEpJHN5bWJvbApkZWdzLkJQID0gc3Vic2V0KHJlcy5ULCBjb25kaXRpb24gPT0gJ0I6IFdNTCB2cyBOQVdNJyAmIGFkai5QLlZhbDwwLjA1ICYgYWJzKGxvZ0ZDKT4xKSRzeW1ib2wKZGVncy5DUCA9IHN1YnNldChyZXMuVCwgY29uZGl0aW9uID09ICdDOiBXTUwgdnMgQ1dNJyAmIGFkai5QLlZhbDwwLjA1ICYgYWJzKGxvZ0ZDKT4xKSRzeW1ib2wKCnJlcy5UJHNpZ24gPSAnTlMnCnJlcy5UW3doaWNoKHJlcy5UJGFkai5QLlZhbDwwLjA1ICYgcmVzLlQkbG9nRkM+MSksJ3NpZ24nXT0nVVAnCnJlcy5UW3doaWNoKHJlcy5UJGFkai5QLlZhbDwwLjA1ICYgcmVzLlQkbG9nRkM8KC0xKSksJ3NpZ24nXT0nRE4nCnJlcy5CUCRzaWduID0gJ05TJwpyZXMuQlBbd2hpY2gocmVzLkJQJGFkai5QLlZhbDwwLjA1ICYgcmVzLkJQJGxvZ0ZDPjEpLCdzaWduJ109J1VQJwpyZXMuQlBbd2hpY2gocmVzLkJQJGFkai5QLlZhbDwwLjA1ICYgcmVzLkJQJGxvZ0ZDPCgtMSkpLCdzaWduJ109J0ROJwoKCiMjIwpyZXMuQlA8LW5hLm9taXQocmVzLkJQW29yZGVyKC1yZXMuQlAkbG9nRkMpLF0pCmdncGxvdChyZXMuVCxhZXMoeD1sb2dGQyx5PS1sb2cxMChQLlZhbHVlKSkpK2dlb21fcG9pbnQoYWVzKGNvbD1zaWduKSkrdGhlbWVfYncoKStzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPXNpZ25fY29scykrZ2VvbV9wb2ludChkYXRhPXJlcy5CUFsxOjEwLF0sIGNvbD0iYmxhY2siKSArZ2VvbV9sYWJlbF9yZXBlbChkYXRhPXJlcy5CUFsxOjMwLF0sYWVzKGxhYmVsPXN5bWJvbCksZm9yY2U9MTAsc2l6ZSA9IDIsZmlsbCA9IGFscGhhKGMoIndoaXRlIiksMC41KSkgK3RoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIixzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGw9YygiZ3JleTk1IikpKQojIyMKCnJlcy5BUDwtbmEub21pdChyZXMuQVBbb3JkZXIocmVzLkFQJFAuVmFsdWUpLF0pCnJlcy5CUDwtbmEub21pdChyZXMuQlBbb3JkZXIocmVzLkJQJFAuVmFsdWUpLF0pCnJlcy5DUDwtbmEub21pdChyZXMuQ1Bbb3JkZXIocmVzLkNQJFAuVmFsdWUpLF0pCmBgYAoKIyMjIFZvbGNhbm8gcGxvdCB3aXRoIHRoZSB0b3AgMTAgc2lnbmlmaWNhbnQgZ2VuZXMKYGBge3IgIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcGFnZWQucHJpbnQ9RkFMU0UsIGZpZy53aWR0aCA9IDYsIGZpZy5oZWlnaHQgPSA0fQpvcHRpb25zKGdncmVwZWwubWF4Lm92ZXJsYXBzID0gSW5mKQp2b2xjYW5vVG9wMTAgPC0gZ2dwbG90KHJlcy5ULGFlcyh4PWxvZ0ZDLHk9LWxvZzEwKFAuVmFsdWUpKSkrZ2VvbV9wb2ludChhZXMoY29sPXNpZ24pKSt0aGVtZV9idygpK3NjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygnZGVlcHNreWJsdWUnLCdncmV5NzUnLCd0b21hdG8nKSkrCiAgZ2VvbV9wb2ludChkYXRhPXJlcy5BUFsxOjEwLF0sIGNvbD0iYmxhY2siKSArZ2VvbV9sYWJlbF9yZXBlbChkYXRhPXJlcy5BUFsxOjEwLF0sYWVzKGxhYmVsPXN5bWJvbCksZm9yY2U9MTAsc2l6ZSA9IDIsZmlsbCA9IGFscGhhKGMoIndoaXRlIiksMC41KSkgKyAKICBnZW9tX3BvaW50KGRhdGE9cmVzLkJQWzE6MTAsXSwgY29sPSJibGFjayIpICtnZW9tX2xhYmVsX3JlcGVsKGRhdGE9cmVzLkJQWzE6MTAsXSxhZXMobGFiZWw9c3ltYm9sKSxmb3JjZT0xMCxzaXplID0gMixmaWxsID0gYWxwaGEoYygid2hpdGUiKSwwLjUpKSArIAogIGdlb21fcG9pbnQoZGF0YT1yZXMuQ1BbMToxMCxdLCBjb2w9ImJsYWNrIikgK2dlb21fbGFiZWxfcmVwZWwoZGF0YT1yZXMuQ1BbMToxMCxdLGFlcyhsYWJlbD1zeW1ib2wpLGZvcmNlPTEwLHNpemUgPSAyLGZpbGwgPSBhbHBoYShjKCJ3aGl0ZSIpLDAuNSkpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbD1jKCJncmV5OTUiKSkpKyBmYWNldF93cmFwKH5jb25kaXRpb24pCnZvbGNhbm9Ub3AxMApgYGAKCiMjIyBWb2xjYW5vIHBsb3Qgd2l0aCBnZW5lcyBvZiBpbnRlcmVzdCAodG9wIHNpZ25pZmljYW50IGdlbmVzIGZyb20gQnVsayk7CgoqSUNBTTEsVkNBTTEsIkROQUg1IiwiQ0lCQVIyIiwiTFJSSVExIiwiT0RBRDIiLCJDRDI0IiwiRExFQzEiLCJDRkFQNTQiLCJGSEFEMSIsIkRZTkxUNSIsIkNGQVA0MyIsIlJTUEgxIiwiRE5BSTMiKgpgYGB7ciAgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBwYWdlZC5wcmludD1UUlVFLCBmaWcud2lkdGggPSA2LCBmaWcuaGVpZ2h0ID0gNH0KcmVzPXJlc1tvcmRlcihyZXMkUC5WYWx1ZSksXQoKZ2VuZWxhYmVsc1AgPC0gYygiQ0QyNCIpCmdlbmVMYWJlbHNQMiA8LSB1bmlxdWUoaGVhZChyZXNBJGdlbmVfbmFtZSwzMCkpCmdlbmVsYWJlbHNQIDwtIGFwcGVuZChnZW5lbGFiZWxzUCwgZ2VuZUxhYmVsc1AyKQoKCiMjIyMgcHV0IGdlbmUgb2YgdGhlIHB1YmxpYyBkYXRhIG9uIG91ciBjb21wYXJhaXNvbgoKI2dlbmVMYWJlbHNQdWIgPC0gdW5pcXVlKGhlYWQocmVzLkJQJHN5bWJvbCwzMCkpCiNnZW5lTGFiZWxzUHViU2lnbmlmaWNhbnQgPC0gc3Vic2V0KHJlcy5CUCxzaWduPT0iVVAiKQojZ2VuZUxhYmVsc1B1YlNpZ25pZmljYW50IDwtIHVuaXF1ZShnZW5lTGFiZWxzUHViU2lnbmlmaWNhbnQkc3ltYm9sKQoKI2dncGxvdChyZXNBLGFlcyh4PWxvZ0ZDLHk9LWxvZzEwKFAuVmFsdWUpKSkrZ2VvbV9wb2ludChhZXMoY29sPXNpZ24pKSsgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1zaWduX2NvbHMpKyBnZW9tX3BvaW50KGRhdGE9cmVzQVttYXRjaChnZW5lTGFiZWxzUHViLCByZXNBJGdlbmVfbmFtZSksXSwgY29sPSJibGFjayIpICtnZW9tX2xhYmVsX3JlcGVsKGRhdGE9cmVzQVttYXRjaChnZW5lTGFiZWxzUHViJHN5bWJvbCwgcmVzQSRnZW5lX25hbWUpLF0sYWVzKGxhYmVsPWdlbmVMYWJlbHNQdWIpLGZvcmNlPTEwLHNpemUgPSAzLjUsZmlsbCA9IGFscGhhKGMoIndoaXRlIiksMC41KSxmb250ZmFjZSA9ICdib2xkJykrIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIixzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGw9YygiZ3JleTk1IikpKSt0aGVtZV9idygpK2dndGl0bGUoIldNTCB2cyBOQVdNIikKIyMjCgpwMSA9IGdncGxvdChzdWJzZXQocmVzLlQsY29uZGl0aW9uPT0iQTogTkFXTSB2cyBDV00iKSxhZXMoeD1sb2dGQyx5PS1sb2cxMChQLlZhbHVlKSkpK2dlb21fcG9pbnQoYWVzKGNvbD1zaWduKSkrIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygnZGVlcHNreWJsdWUnLCdncmV5NzUnLCd0b21hdG8nKSkrIGdlb21fcG9pbnQoZGF0YT1yZXMuQVBbbWF0Y2goZ2VuZWxhYmVsc1AsIHJlcy5BUCRzeW1ib2wpLF0sIGNvbD0iYmxhY2siKSArZ2VvbV9sYWJlbF9yZXBlbChkYXRhPXJlcy5BUFttYXRjaChnZW5lbGFiZWxzUCwgcmVzLkFQJHN5bWJvbCksXSxhZXMobGFiZWw9Z2VuZWxhYmVsc1ApLGZvcmNlPTEwLHNpemUgPSAzLjUsZmlsbCA9IGFscGhhKGMoIndoaXRlIiksMC41KSxmb250ZmFjZSA9ICdib2xkJykrIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIixzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGw9YygiZ3JleTk1IikpKSt0aGVtZV9idygpK2dndGl0bGUoIkE6IE5BV00gdnMgQ1dNIikKCnAyID0gZ2dwbG90KHN1YnNldChyZXMuVCxjb25kaXRpb249PSdCOiBXTUwgdnMgTkFXTScpLGFlcyh4PWxvZ0ZDLHk9LWxvZzEwKFAuVmFsdWUpKSkrZ2VvbV9wb2ludChhZXMoY29sPXNpZ24pKSsgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCdkZWVwc2t5Ymx1ZScsJ2dyZXk3NScsJ3RvbWF0bycpKSsgZ2VvbV9wb2ludChkYXRhPXJlcy5CUFttYXRjaChnZW5lbGFiZWxzUCwgcmVzLkJQJHN5bWJvbCksXSwgY29sPSJibGFjayIpICtnZW9tX2xhYmVsX3JlcGVsKGRhdGE9cmVzLkJQW21hdGNoKGdlbmVsYWJlbHNQLCByZXMuQlAkc3ltYm9sKSxdLGFlcyhsYWJlbD1nZW5lbGFiZWxzUCksZm9yY2U9MTAsc2l6ZSA9IDMuNSxmaWxsID0gYWxwaGEoYygid2hpdGUiKSwwLjUpLGZvbnRmYWNlID0gJ2JvbGQnKSsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbD1jKCJncmV5OTUiKSkpK3RoZW1lX2J3KCkrZ2d0aXRsZSgiQjogV01MIHZzIE5BV00iKQoKcDMgPSBnZ3Bsb3Qoc3Vic2V0KHJlcy5ULGNvbmRpdGlvbj09J0M6IFdNTCB2cyBDV00nKSxhZXMoeD1sb2dGQyx5PS1sb2cxMChQLlZhbHVlKSkpK2dlb21fcG9pbnQoYWVzKGNvbD1zaWduKSkrIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygnZGVlcHNreWJsdWUnLCdncmV5NzUnLCd0b21hdG8nKSkrIGdlb21fcG9pbnQoZGF0YT1yZXMuQ1BbbWF0Y2goZ2VuZWxhYmVsc1AsIHJlcy5DUCRzeW1ib2wpLF0sIGNvbD0iYmxhY2siKSArZ2VvbV9sYWJlbF9yZXBlbChkYXRhPXJlcy5DUFttYXRjaChnZW5lbGFiZWxzUCwgcmVzLkNQJHN5bWJvbCksXSxhZXMobGFiZWw9Z2VuZWxhYmVsc1ApLGZvcmNlPTEwLHNpemUgPSAzLjUsZmlsbCA9IGFscGhhKGMoIndoaXRlIiksMC41KSxmb250ZmFjZSA9ICdib2xkJykrIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIixzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGw9YygiZ3JleTk1IikpKSt0aGVtZV9idygpK2dndGl0bGUoIkM6IFdNTCB2cyBDV00iKQoKZ2dhcnJhbmdlKAogIHAxLHAyLHAzLCBjb21tb24ubGVnZW5kID0gVFJVRSwgbGVnZW5kID0gImJvdHRvbSIsIG5jb2wgPSAzKQoKYGBgCgojIyBCb3hwbG90cyBvZiBzZWxlY3QgZ2VuZXMgZGVtb25zdHJhdGluZyBzaWduaWZpY2FudCBkaWZmZXJlbnRpYWwgZ2VuZSBleHByZXNzaW9uLgoKYGBge3IsIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcGFnZWQucHJpbnQ9RkFMU0UsIGZpZy53aWR0aCA9IDgsIGZpZy5oZWlnaHQgPSA3fQojQ0lCQVIyIDwtIHBsb3QuZ2VuZVAoIkNJQkFSMiIsY29scz1jb25fY29sb3JzUCkKRE5BSDUgPC0gcGxvdC5nZW5lUCgiRE5BSDUiLGNvbHM9Y29uX2NvbG9yc1ApCiNpcmYxIDwtIHBsb3QuZ2VuZVAoIklSRjEiLGNvbHM9Y29uX2NvbG9yc1ApCkxSUklRMSA8LSBwbG90LmdlbmVQKCJMUlJJUTEiLGNvbHM9Y29uX2NvbG9yc1ApCmljYW0xIDwtIHBsb3QuZ2VuZVAoIklDQU0xIixjb2xzPWNvbl9jb2xvcnNQKQpPREFEMiA8LSBwbG90LmdlbmVQKCJPREFEMiIsY29scz1jb25fY29sb3JzUCkKdmNhbTEgPC0gcGxvdC5nZW5lUCgiVkNBTTEiLGNvbHM9Y29uX2NvbG9yc1ApCiNDRDI0IDwtIHBsb3QuZ2VuZVAoIkNEMjQiLGNvbHM9Y29uX2NvbG9yc1ApCmRsZWMxIDwtIHBsb3QuZ2VuZVAoIkRMRUMxIixjb2xzPWNvbl9jb2xvcnNQKQpjZmFwNTQgPC0gcGxvdC5nZW5lUCgiQ0ZBUDU0Iixjb2xzPWNvbl9jb2xvcnNQKQpmaGFkMSA8LSBwbG90LmdlbmVQKCJGSEFEMSIsY29scz1jb25fY29sb3JzUCkKZHlubHQ1IDwtIHBsb3QuZ2VuZVAoIkRZTkxUNSIsY29scz1jb25fY29sb3JzUCkKY2ZhcDQzIDwtIHBsb3QuZ2VuZVAoIkNGQVA0MyIsY29scz1jb25fY29sb3JzUCkKcnNwaDEgPC0gcGxvdC5nZW5lUCgiUlNQSDEiLGNvbHM9Y29uX2NvbG9yc1ApCmRuYWkzIDwtIHBsb3QuZ2VuZVAoIkROQUkzIixjb2xzPWNvbl9jb2xvcnNQKQojY3hjbDE0IDwtIHBsb3QuZ2VuZVAoIkNYQ0wxNCIsY29scz1jb25fY29sb3JzUCkKZ2dhcnJhbmdlKEROQUg1LCBMUlJJUTEsIE9EQUQyLCBpY2FtMSwgZGxlYzEsIGNmYXA1NCwgdmNhbTEsIGZoYWQxLCBkeW5sdDUsIGNmYXA0MywgcnNwaDEsIGRuYWkzLCBuY29sID0gMywgbnJvdyA9IDQsYWxpZ24gPSBjKCJodiIpLCBjb21tb24ubGVnZW5kID0gVFJVRSwgbGVnZW5kPSJib3R0b20iKQpgYGAKCiMgR2VuZSBPbnRvbG9neSBlbnJpY2htZW50IGFuYWx5c2lzIChUb3AgcGF0aHdheSkgey50YWJzZXR9CgojIyBCaW9sb2dpY2FsIFByb2Nlc3Mgey50YWJzZXR9CmBgYHtyIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcGFnZWQucHJpbnQ9RkFMU0UsIGZpZy53aWR0aCA9IDgsIGZpZy5oZWlnaHQgPSA3fQojI3BhdGh3YXkKc3BlY2lmaWNBUCA9IGFzLmNoYXJhY3RlcihuYS5vbWl0KGRlZ3MuQVBbIWRlZ3MuQVAlaW4lZGVncy5CUCAmICFkZWdzLkFQJWluJWRlZ3MuQ1BdKSkKc3BlY2lmaWNCUCA9IGFzLmNoYXJhY3RlcihuYS5vbWl0KGRlZ3MuQlBbIWRlZ3MuQlAlaW4lZGVncy5BUCAmICFkZWdzLkJQJWluJWRlZ3MuQ1BdKSkKc3BlY2lmaWNDUCA9IGFzLmNoYXJhY3RlcihuYS5vbWl0KGRlZ3MuQ1BbIWRlZ3MuQ1AlaW4lZGVncy5BUCAmICFkZWdzLkNQJWluJWRlZ3MuQlBdKSkKCmxpc3RQID0gbGlzdChzcGVjaWZpY0FQPXNwZWNpZmljQVAsIHNwZWNpZmljQlA9c3BlY2lmaWNCUCxzcGVjaWZpY0NQPXNwZWNpZmljQ1ApCmZpc2hQID0gZmlzaGVyX2VucmljaG1lbnQobGlzdFAsZ29CUCx1bmlxdWUocmVzLlQkc3ltYm9sKSkKCiMjdG9wMTAgcGF0aHdheSBCUAp0YWJBUCA8LSBmaXNoUCRzcGVjaWZpY0FQCnRhYkFQJGZkciA8LSBhcy5udW1lcmljKHRhYkFQJGZkcikgCnRhYkFQJE9SLm9kZHMucmF0aW8gPC0gYXMubnVtZXJpYyh0YWJBUCRPUi5vZGRzLnJhdGlvKSAKdGFiQVAkTk9NX3B2YWwgPC0gYXMubnVtZXJpYyh0YWJBUCROT01fcHZhbCkKdG9wQVAgPC0gdG9wUGF0aChmaXNoUCAsInNwZWNpZmljQVAiLCAwLjUsIDE0KQp0YWJBUDEgPC0gdGFiQVBbbWF0Y2godG9wQVAsIHJvd25hbWVzKHRhYkFQKSksXQpyb3duYW1lcyh0YWJBUDEpIDwtIGdzdWIoIkdPQlBfIiwgIiIscm93bmFtZXModGFiQVAxKSkgCnJvd25hbWVzKHRhYkFQMSkgPC0gZ3N1YigiXyIsICIgIixyb3duYW1lcyh0YWJBUDEpKSAKcm93bmFtZXModGFiQVApIDwtIGdzdWIoIkdPQlBfIiwgIiIscm93bmFtZXModGFiQVApKSAKcm93bmFtZXModGFiQVApIDwtIGdzdWIoIl8iLCAiICIscm93bmFtZXModGFiQVApKSAKCnRhYkJQIDwtIGZpc2hQJHNwZWNpZmljQlAKdGFiQlAkZmRyIDwtIGFzLm51bWVyaWModGFiQlAkZmRyKQp0YWJCUCRPUi5vZGRzLnJhdGlvIDwtIGFzLm51bWVyaWModGFiQlAkT1Iub2Rkcy5yYXRpbykgCnRhYkJQJE5PTV9wdmFsIDwtIGFzLm51bWVyaWModGFiQlAkTk9NX3B2YWwpCnRvcEJQIDwtIHRvcFBhdGgoZmlzaFAgLCJzcGVjaWZpY0JQIiwgMC41LCAxNCkKdGFiQlAxIDwtIHRhYkJQW21hdGNoKHRvcEJQLCByb3duYW1lcyh0YWJCUCkpLF0Kcm93bmFtZXModGFiQlAxKSA8LSBnc3ViKCJHT0JQXyIsICIiLHJvd25hbWVzKHRhYkJQMSkpIApyb3duYW1lcyh0YWJCUDEpIDwtIGdzdWIoIl8iLCAiICIscm93bmFtZXModGFiQlAxKSkgCnJvd25hbWVzKHRhYkJQKSA8LSBnc3ViKCJHT0JQXyIsICIiLHJvd25hbWVzKHRhYkJQKSkgCnJvd25hbWVzKHRhYkJQKSA8LSBnc3ViKCJfIiwgIiAiLHJvd25hbWVzKHRhYkJQKSkgCgp0YWJDUCA8LSBmaXNoUCRzcGVjaWZpY0NQCnRhYkNQJGZkciA8LSBhcy5udW1lcmljKHRhYkNQJGZkcikKdGFiQ1AkT1Iub2Rkcy5yYXRpbyA8LSBhcy5udW1lcmljKHRhYkNQJE9SLm9kZHMucmF0aW8pIAp0YWJDUCROT01fcHZhbCA8LSBhcy5udW1lcmljKHRhYkNQJE5PTV9wdmFsKQp0b3BDUCA8LSB0b3BQYXRoKGZpc2hQICwic3BlY2lmaWNDUCIsIDAuNSwgMTQpCnRhYkNQMSA8LSB0YWJDUFttYXRjaCh0b3BDUCwgcm93bmFtZXModGFiQ1ApKSxdCnJvd25hbWVzKHRhYkNQMSkgPC0gZ3N1YigiR09CUF8iLCAiIixyb3duYW1lcyh0YWJDUDEpKSAKcm93bmFtZXModGFiQ1AxKSA8LSBnc3ViKCJfIiwgIiAiLHJvd25hbWVzKHRhYkNQMSkpIApyb3duYW1lcyh0YWJDUCkgPC0gZ3N1YigiR09CUF8iLCAiIixyb3duYW1lcyh0YWJDUCkpIApyb3duYW1lcyh0YWJDUCkgPC0gZ3N1YigiXyIsICIgIixyb3duYW1lcyh0YWJDUCkpIApgYGAKCgojIyMgVG9wIDEwIHBhdGh3YXkgQ1dNIHZzIE5BV00KYGBge3IgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBwYWdlZC5wcmludD1GQUxTRSwgZmlnLndpZHRoID0gNCwgZmlnLmhlaWdodCA9IDN9CmdncGxvdCh0YWJBUDEsIGFlcyh4PXJlb3JkZXIocm93bmFtZXModGFiQVAxKSwtcmFuayhOT01fcHZhbCkpLCB5PS1sb2cxMChOT01fcHZhbCksZmlsbD0tbG9nMTAoTk9NX3B2YWwpKSkgK2dlb21fY29sKHdpZHRoPS42NSkrIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93PSIjRjZCREMwIixoaWdoPSIjREMxQzEzIikgK3RoZW1lKGF4aXMudGV4dD1lbGVtZW50X3RleHQoc2l6ZT04KSkgKyBzY2FsZV94X2Rpc2NyZXRlKGxhYmVsID0gZnVuY3Rpb24oeCkgc3RyaW5ncjo6c3RyX3dyYXAoZ3N1YigiXyIsICIgIix4KSwgd2lkdGggPSAzMCkpICsgbGFicyh0aXRsZSA9ICJDV00gdnMgTkFXTSIsIHN1YnRpdGxlID0gIkdPIEJpb2xvZ2ljYWwgUHJvY2VzcyAyMDIxIikgKyB4bGFiKCIiKSArIGNvb3JkX2ZsaXAoKSArIHRoZW1lX2J3KCkrIHRoZW1lKGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChmYWNlPSJib2xkIikpCmBgYAoKCiMjIyBUb3AgMTAgcGF0aHdheSBOQVdNIHZzIFdNTApgYGB7ciBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIHBhZ2VkLnByaW50PUZBTFNFLCBmaWcud2lkdGggPSA0LCBmaWcuaGVpZ2h0ID0gM30KZ2dwbG90KHRhYkJQMSwgYWVzKHg9cmVvcmRlcihyb3duYW1lcyh0YWJCUDEpLC1yYW5rKE5PTV9wdmFsKSksIHk9LWxvZzEwKE5PTV9wdmFsKSxmaWxsPS1sb2cxMChOT01fcHZhbCkpKSArZ2VvbV9jb2wod2lkdGg9LjY1KSsgc2NhbGVfZmlsbF9ncmFkaWVudChsb3c9IiNGNkJEQzAiLGhpZ2g9IiNEQzFDMTMiKSt0aGVtZShheGlzLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9OCkpICsgc2NhbGVfeF9kaXNjcmV0ZShsYWJlbCA9IGZ1bmN0aW9uKHgpIHN0cmluZ3I6OnN0cl93cmFwKGdzdWIoIl8iLCAiICIseCksIHdpZHRoID0gMzApKSArIHhsYWIoIiIpKyBsYWJzKHRpdGxlID0gIk5BV00gdnMgV01MIiwgc3VidGl0bGUgPSAiR08gQmlvbG9naWNhbCBQcm9jZXNzIDIwMjEiKSArIGNvb3JkX2ZsaXAoKSsgdGhlbWVfYncoKSsgdGhlbWUoYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KGZhY2U9ImJvbGQiKSkKYGBgCgoKIyMjIFRvcCAxMCBwYXRod2F5IENXTSB2cyBXTUwKYGBge3IgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBwYWdlZC5wcmludD1GQUxTRSwgZmlnLndpZHRoID0gNCwgZmlnLmhlaWdodCA9IDN9CmdncGxvdCh0YWJDUDEsIGFlcyh4PXJlb3JkZXIocm93bmFtZXModGFiQ1AxKSwtcmFuayhOT01fcHZhbCkpLCB5PS1sb2cxMChOT01fcHZhbCksZmlsbD0tbG9nMTAoTk9NX3B2YWwpKSkgK2dlb21fY29sKHdpZHRoPS42NSkrIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93PSIjRjZCREMwIixoaWdoPSIjREMxQzEzIikrdGhlbWUoYXhpcy50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTgpKSArIHNjYWxlX3hfZGlzY3JldGUobGFiZWwgPSBmdW5jdGlvbih4KSBzdHJpbmdyOjpzdHJfd3JhcChnc3ViKCJfIiwgIiAiLHgpLCB3aWR0aCA9IDMwKSkgKyB4bGFiKCIiKSsgbGFicyggdGl0bGUgPSAiQ1dNIHZzIFdNTCIsIHN1YnRpdGxlID0gIkdPIE1vbGVjdWxhciBGdW5jdGlvbiAyMDIxIikgKyBjb29yZF9mbGlwKCkrdGhlbWVfYncoKSsgdGhlbWUoYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KGZhY2U9ImJvbGQiKSkKYGBgCgojIyBNb2xlY3VsYXIgRnVuY3Rpb24gey50YWJzZXR9CmBgYHtyIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcGFnZWQucHJpbnQ9RkFMU0UsIGZpZy53aWR0aCA9IDgsIGZpZy5oZWlnaHQgPSA3fQojI3BhdGh3YXkKc3BlY2lmaWNBUCA9IGFzLmNoYXJhY3RlcihuYS5vbWl0KGRlZ3MuQVBbIWRlZ3MuQVAlaW4lZGVncy5CUCAmICFkZWdzLkFQJWluJWRlZ3MuQ1BdKSkKc3BlY2lmaWNCUCA9IGFzLmNoYXJhY3RlcihuYS5vbWl0KGRlZ3MuQlBbIWRlZ3MuQlAlaW4lZGVncy5BUCAmICFkZWdzLkJQJWluJWRlZ3MuQ1BdKSkKc3BlY2lmaWNDUCA9IGFzLmNoYXJhY3RlcihuYS5vbWl0KGRlZ3MuQ1BbIWRlZ3MuQ1AlaW4lZGVncy5BUCAmICFkZWdzLkNQJWluJWRlZ3MuQlBdKSkKCmxpc3RQID0gbGlzdChzcGVjaWZpY0FQPXNwZWNpZmljQVAsIHNwZWNpZmljQlA9c3BlY2lmaWNCUCxzcGVjaWZpY0NQPXNwZWNpZmljQ1ApCmZpc2hQID0gZmlzaGVyX2VucmljaG1lbnQobGlzdFAsbWYsdW5pcXVlKHJlcy5UJHN5bWJvbCkpCgojI3RvcDEwIHBhdGh3YXkgTUYKdGFiQVAgPC0gZmlzaFAkc3BlY2lmaWNBUAp0YWJBUCRmZHIgPC0gYXMubnVtZXJpYyh0YWJBUCRmZHIpIAp0YWJBUCRPUi5vZGRzLnJhdGlvIDwtIGFzLm51bWVyaWModGFiQVAkT1Iub2Rkcy5yYXRpbykgCnRhYkFQJE5PTV9wdmFsIDwtIGFzLm51bWVyaWModGFiQVAkTk9NX3B2YWwpCnRvcEFQIDwtIHRvcFBhdGgoZmlzaFAgLCJzcGVjaWZpY0FQIiwgMC41LCAxMikKdGFiQVAxIDwtIHRhYkFQW21hdGNoKHRvcEFQLCByb3duYW1lcyh0YWJBUCkpLF0Kcm93bmFtZXModGFiQVAxKSA8LSBnc3ViKCJHT01GXyIsICIiLHJvd25hbWVzKHRhYkFQMSkpIApyb3duYW1lcyh0YWJBUDEpIDwtIGdzdWIoIl8iLCAiICIscm93bmFtZXModGFiQVAxKSkgCnJvd25hbWVzKHRhYkFQKSA8LSBnc3ViKCJHT01GXyIsICIiLHJvd25hbWVzKHRhYkFQKSkgCnJvd25hbWVzKHRhYkFQKSA8LSBnc3ViKCJfIiwgIiAiLHJvd25hbWVzKHRhYkFQKSkgCgp0YWJCUCA8LSBmaXNoUCRzcGVjaWZpY0JQCnRhYkJQJGZkciA8LSBhcy5udW1lcmljKHRhYkJQJGZkcikKdGFiQlAkT1Iub2Rkcy5yYXRpbyA8LSBhcy5udW1lcmljKHRhYkJQJE9SLm9kZHMucmF0aW8pIAp0YWJCUCROT01fcHZhbCA8LSBhcy5udW1lcmljKHRhYkJQJE5PTV9wdmFsKQp0YWJCUD10YWJCUFtvcmRlcih0YWJCUCROT01fcHZhbCksXQp0b3BCUCA9IHN1YnNldCh0YWJCUCxOT01fcHZhbDw9MC4wNSkKdG9wQlAkcGF0aHdheSA9IHJvd25hbWVzKHRvcEJQKQp0YWJCUDEgPC0gdGFiQlBbbWF0Y2gocm93bmFtZXModG9wQlApLCByb3duYW1lcyh0YWJCUCkpLF0KdGFiQlAxIDwtIHRhYkJQMVstYyg4LCA5LCAxNCwgMTUpLCBdCnRhYkJQMSA8LSB0YWJCUDFbMToxMixdCnJvd25hbWVzKHRhYkJQMSkgPC0gZ3N1YigiR09NRl8iLCAiIixyb3duYW1lcyh0YWJCUDEpKSAKcm93bmFtZXModGFiQlAxKSA8LSBnc3ViKCJfIiwgIiAiLHJvd25hbWVzKHRhYkJQMSkpIApyb3duYW1lcyh0YWJCUCkgPC0gZ3N1YigiR09NRl8iLCAiIixyb3duYW1lcyh0YWJCUCkpIApyb3duYW1lcyh0YWJCUCkgPC0gZ3N1YigiXyIsICIgIixyb3duYW1lcyh0YWJCUCkpIAoKdGFiQ1AgPC0gZmlzaFAkc3BlY2lmaWNDUAp0YWJDUCRmZHIgPC0gYXMubnVtZXJpYyh0YWJDUCRmZHIpCnRhYkNQJE9SLm9kZHMucmF0aW8gPC0gYXMubnVtZXJpYyh0YWJDUCRPUi5vZGRzLnJhdGlvKSAKdGFiQ1AkTk9NX3B2YWwgPC0gYXMubnVtZXJpYyh0YWJDUCROT01fcHZhbCkKdG9wQ1AgPC0gdG9wUGF0aChmaXNoUCAsInNwZWNpZmljQ1AiLCAwLjUsIDEyKQp0YWJDUDEgPC0gdGFiQ1BbbWF0Y2godG9wQ1AsIHJvd25hbWVzKHRhYkNQKSksXQpyb3duYW1lcyh0YWJDUDEpIDwtIGdzdWIoIkdPTUZfIiwgIiIscm93bmFtZXModGFiQ1AxKSkgCnJvd25hbWVzKHRhYkNQMSkgPC0gZ3N1YigiXyIsICIgIixyb3duYW1lcyh0YWJDUDEpKSAKcm93bmFtZXModGFiQ1ApIDwtIGdzdWIoIkdPTUZfIiwgIiIscm93bmFtZXModGFiQ1ApKSAKcm93bmFtZXModGFiQ1ApIDwtIGdzdWIoIl8iLCAiICIscm93bmFtZXModGFiQ1ApKSAKYGBgCgoKIyMjIFRvcCAxMCBwYXRod2F5IENXTSB2cyBOQVdNCmBgYHtyIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcGFnZWQucHJpbnQ9RkFMU0UsIGZpZy53aWR0aCA9IDQsIGZpZy5oZWlnaHQgPSAzfQpnZ3Bsb3QodGFiQVAxLCBhZXMoeD1yZW9yZGVyKHJvd25hbWVzKHRhYkFQMSksLXJhbmsoTk9NX3B2YWwpKSwgeT0tbG9nMTAoTk9NX3B2YWwpLGZpbGw9LWxvZzEwKE5PTV9wdmFsKSkpICtnZW9tX2NvbCh3aWR0aD0uNjUpKyBzY2FsZV9maWxsX2dyYWRpZW50KGxvdz0iI0Y2QkRDMCIsaGlnaD0iI0RDMUMxMyIpICt0aGVtZShheGlzLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9OCkpICsgc2NhbGVfeF9kaXNjcmV0ZShsYWJlbCA9IGZ1bmN0aW9uKHgpIHN0cmluZ3I6OnN0cl93cmFwKGdzdWIoIl8iLCAiICIseCksIHdpZHRoID0gMzApKSArIGxhYnModGl0bGUgPSAiQ1dNIHZzIE5BV00iLCBzdWJ0aXRsZSA9ICJHTyBNb2xlY3VsYXIgRnVuY3Rpb24gMjAyMSIpICsgeGxhYigiIikgKyBjb29yZF9mbGlwKCkgKyB0aGVtZV9idygpKyB0aGVtZShheGlzLnRleHQgPSBlbGVtZW50X3RleHQoZmFjZT0iYm9sZCIpKQpgYGAKCgojIyMgVG9wIDEwIHBhdGh3YXkgTkFXTSB2cyBXTUwKYGBge3IgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBwYWdlZC5wcmludD1GQUxTRSwgZmlnLndpZHRoID0gNCwgZmlnLmhlaWdodCA9IDN9CmdncGxvdCh0YWJCUDEsIGFlcyh4PXJlb3JkZXIocm93bmFtZXModGFiQlAxKSwtcmFuayhOT01fcHZhbCkpLCB5PS1sb2cxMChOT01fcHZhbCksZmlsbD0tbG9nMTAoTk9NX3B2YWwpKSkgK2dlb21fY29sKHdpZHRoPS42NSkrIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93PSIjRjZCREMwIixoaWdoPSIjREMxQzEzIikrdGhlbWUoYXhpcy50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTgpKSArIHNjYWxlX3hfZGlzY3JldGUobGFiZWwgPSBmdW5jdGlvbih4KSBzdHJpbmdyOjpzdHJfd3JhcChnc3ViKCJfIiwgIiAiLHgpLCB3aWR0aCA9IDMwKSkgKyB4bGFiKCIiKSsgbGFicyh0aXRsZSA9ICJOQVdNIHZzIFdNTCIsIHN1YnRpdGxlID0gIkdPIE1vbGVjdWxhciBGdW5jdGlvbiAyMDIxIikgKyBjb29yZF9mbGlwKCkrIHRoZW1lX2J3KCkrIHRoZW1lKGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChmYWNlPSJib2xkIikpCmBgYAoKCiMjIyBUb3AgMTAgcGF0aHdheSBDV00gdnMgV01MCmBgYHtyIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcGFnZWQucHJpbnQ9RkFMU0UsIGZpZy53aWR0aCA9IDQsIGZpZy5oZWlnaHQgPSAzfQpnZ3Bsb3QodGFiQ1AxLCBhZXMoeD1yZW9yZGVyKHJvd25hbWVzKHRhYkNQMSksLXJhbmsoTk9NX3B2YWwpKSwgeT0tbG9nMTAoTk9NX3B2YWwpLGZpbGw9LWxvZzEwKE5PTV9wdmFsKSkpICtnZW9tX2NvbCh3aWR0aD0uNjUpKyBzY2FsZV9maWxsX2dyYWRpZW50KGxvdz0iI0Y2QkRDMCIsaGlnaD0iI0RDMUMxMyIpK3RoZW1lKGF4aXMudGV4dD1lbGVtZW50X3RleHQoc2l6ZT04KSkgKyBzY2FsZV94X2Rpc2NyZXRlKGxhYmVsID0gZnVuY3Rpb24oeCkgc3RyaW5ncjo6c3RyX3dyYXAoZ3N1YigiXyIsICIgIix4KSwgd2lkdGggPSAzMCkpICsgeGxhYigiIikrIGxhYnMoIHRpdGxlID0gIkNXTSB2cyBXTUwiLCBzdWJ0aXRsZSA9ICJHTyBNb2xlY3VsYXIgRnVuY3Rpb24gMjAyMSIpICsgY29vcmRfZmxpcCgpK3RoZW1lX2J3KCkrIHRoZW1lKGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChmYWNlPSJib2xkIikpCmBgYAoKIyMgVHJhbnNjcmlwdGlvbiBmYWN0b3IgdGFyZ2V0cyB7LnRhYnNldH0KYGBge3IgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBwYWdlZC5wcmludD1GQUxTRSwgZmlnLndpZHRoID0gOCwgZmlnLmhlaWdodCA9IDd9CiMjcGF0aHdheQpzcGVjaWZpY0FQID0gYXMuY2hhcmFjdGVyKG5hLm9taXQoZGVncy5BUFshZGVncy5BUCVpbiVkZWdzLkJQICYgIWRlZ3MuQVAlaW4lZGVncy5DUF0pKQpzcGVjaWZpY0JQID0gYXMuY2hhcmFjdGVyKG5hLm9taXQoZGVncy5CUFshZGVncy5CUCVpbiVkZWdzLkFQICYgIWRlZ3MuQlAlaW4lZGVncy5DUF0pKQpzcGVjaWZpY0NQID0gYXMuY2hhcmFjdGVyKG5hLm9taXQoZGVncy5DUFshZGVncy5DUCVpbiVkZWdzLkFQICYgIWRlZ3MuQ1AlaW4lZGVncy5CUF0pKQoKbGlzdFAgPSBsaXN0KHNwZWNpZmljQVA9c3BlY2lmaWNBUCwgc3BlY2lmaWNCUD1zcGVjaWZpY0JQLHNwZWNpZmljQ1A9c3BlY2lmaWNDUCkKZmlzaFAgPSBmaXNoZXJfZW5yaWNobWVudChsaXN0UCx0ZnQsdW5pcXVlKHJlcy5UJHN5bWJvbCkpCgojI3RvcDEwIHBhdGh3YXkgVEZUCnRhYkFQIDwtIGZpc2hQJHNwZWNpZmljQVAKdGFiQVAkZmRyIDwtIGFzLm51bWVyaWModGFiQVAkZmRyKSAKdGFiQVAkT1Iub2Rkcy5yYXRpbyA8LSBhcy5udW1lcmljKHRhYkFQJE9SLm9kZHMucmF0aW8pIAp0YWJBUCROT01fcHZhbCA8LSBhcy5udW1lcmljKHRhYkFQJE5PTV9wdmFsKQp0YWJBUD10YWJBUFtvcmRlcih0YWJBUCROT01fcHZhbCksXQp0b3BBUCA9IHN1YnNldCh0YWJBUCxOT01fcHZhbDw9MC4wNSkKdG9wQVAkcGF0aHdheSA9IHJvd25hbWVzKHRvcEFQKQp0YWJBUDEgPC0gdGFiQVBbbWF0Y2gocm93bmFtZXModG9wQVApLCByb3duYW1lcyh0YWJBUCkpLF0KdGFiQVAxIDwtIHRhYkFQMVsxOjEyLF0Kcm93bmFtZXModGFiQVAxKSA8LSBnc3ViKCJfIiwgIiAiLHJvd25hbWVzKHRhYkFQMSkpIApyb3duYW1lcyh0YWJBUCkgPC0gZ3N1YigiXyIsICIgIixyb3duYW1lcyh0YWJBUCkpIAoKdGFiQlAgPC0gZmlzaFAkc3BlY2lmaWNCUAp0YWJCUCRmZHIgPC0gYXMubnVtZXJpYyh0YWJCUCRmZHIpCnRhYkJQJE9SLm9kZHMucmF0aW8gPC0gYXMubnVtZXJpYyh0YWJCUCRPUi5vZGRzLnJhdGlvKSAKdGFiQlAkTk9NX3B2YWwgPC0gYXMubnVtZXJpYyh0YWJCUCROT01fcHZhbCkKdGFiQlA9dGFiQlBbb3JkZXIodGFiQlAkTk9NX3B2YWwpLF0KdG9wQlAgPSBzdWJzZXQodGFiQlAsTk9NX3B2YWw8PTAuMDUpCnRvcEJQJHBhdGh3YXkgPSByb3duYW1lcyh0b3BCUCkKdGFiQlAxIDwtIHRhYkJQW21hdGNoKHJvd25hbWVzKHRvcEJQKSwgcm93bmFtZXModGFiQlApKSxdCnRhYkJQMSA8LSB0YWJCUDFbMToxMixdCnJvd25hbWVzKHRhYkJQMSkgPC0gZ3N1YigiXyIsICIgIixyb3duYW1lcyh0YWJCUDEpKSAKcm93bmFtZXModGFiQlApIDwtIGdzdWIoIl8iLCAiICIscm93bmFtZXModGFiQlApKSAKCnRhYkNQIDwtIGZpc2hQJHNwZWNpZmljQ1AKdGFiQ1AkZmRyIDwtIGFzLm51bWVyaWModGFiQ1AkZmRyKQp0YWJDUCRPUi5vZGRzLnJhdGlvIDwtIGFzLm51bWVyaWModGFiQ1AkT1Iub2Rkcy5yYXRpbykgCnRhYkNQJE5PTV9wdmFsIDwtIGFzLm51bWVyaWModGFiQ1AkTk9NX3B2YWwpCnRvcENQIDwtIHRvcFBhdGgoZmlzaFAgLCJzcGVjaWZpY0NQIiwgMC41LCAxMikKdGFiQ1AxIDwtIHRhYkNQW21hdGNoKHRvcENQLCByb3duYW1lcyh0YWJDUCkpLF0Kcm93bmFtZXModGFiQ1AxKSA8LSBnc3ViKCJfIiwgIiAiLHJvd25hbWVzKHRhYkNQMSkpIApyb3duYW1lcyh0YWJDUCkgPC0gZ3N1YigiXyIsICIgIixyb3duYW1lcyh0YWJDUCkpIApgYGAKCgojIyMgVG9wIDEwIHBhdGh3YXkgQ1dNIHZzIE5BV00KYGBge3IgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBwYWdlZC5wcmludD1GQUxTRSwgZmlnLndpZHRoID0gNCwgZmlnLmhlaWdodCA9IDN9CmdncGxvdCh0YWJBUDEsIGFlcyh4PXJlb3JkZXIocm93bmFtZXModGFiQVAxKSwtcmFuayhOT01fcHZhbCkpLCB5PS1sb2cxMChOT01fcHZhbCksZmlsbD0tbG9nMTAoTk9NX3B2YWwpKSkgK2dlb21fY29sKHdpZHRoPS42NSkrIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93PSIjRjZCREMwIixoaWdoPSIjREMxQzEzIikgK3RoZW1lKGF4aXMudGV4dD1lbGVtZW50X3RleHQoc2l6ZT04KSkgKyBzY2FsZV94X2Rpc2NyZXRlKGxhYmVsID0gZnVuY3Rpb24oeCkgc3RyaW5ncjo6c3RyX3dyYXAoZ3N1YigiXyIsICIgIix4KSwgd2lkdGggPSAzMCkpICsgbGFicyh0aXRsZSA9ICJDV00gdnMgTkFXTSIsIHN1YnRpdGxlID0gIkdPIFRyYW5zY3JpcHRpb24gZmFjdG9yIHRhcmdldHMgMjAyMSIpICsgeGxhYigiIikgKyBjb29yZF9mbGlwKCkgKyB0aGVtZV9idygpCmBgYAoKCiMjIyBUb3AgMTAgcGF0aHdheSBOQVdNIHZzIFdNTApgYGB7ciBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIHBhZ2VkLnByaW50PUZBTFNFLCBmaWcud2lkdGggPSA0LCBmaWcuaGVpZ2h0ID0gM30KZ2dwbG90KHRhYkJQMSwgYWVzKHg9cmVvcmRlcihyb3duYW1lcyh0YWJCUDEpLC1yYW5rKE5PTV9wdmFsKSksIHk9LWxvZzEwKE5PTV9wdmFsKSxmaWxsPS1sb2cxMChOT01fcHZhbCkpKSArZ2VvbV9jb2wod2lkdGg9LjY1KSsgc2NhbGVfZmlsbF9ncmFkaWVudChsb3c9IiNGNkJEQzAiLGhpZ2g9IiNEQzFDMTMiKSt0aGVtZShheGlzLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9OCkpICsgc2NhbGVfeF9kaXNjcmV0ZShsYWJlbCA9IGZ1bmN0aW9uKHgpIHN0cmluZ3I6OnN0cl93cmFwKGdzdWIoIl8iLCAiICIseCksIHdpZHRoID0gMzApKSArIHhsYWIoIiIpKyBsYWJzKHRpdGxlID0gIk5BV00gdnMgV01MIiwgc3VidGl0bGUgPSAiR08gVHJhbnNjcmlwdGlvbiBmYWN0b3IgdGFyZ2V0cyAyMDIxIikgKyBjb29yZF9mbGlwKCkrIHRoZW1lX2J3KCkKYGBgCgoKIyMjIFRvcCAxMCBwYXRod2F5IENXTSB2cyBXTUwKYGBge3IgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBwYWdlZC5wcmludD1GQUxTRSwgZmlnLndpZHRoID0gNCwgZmlnLmhlaWdodCA9IDN9CmdncGxvdCh0YWJDUDEsIGFlcyh4PXJlb3JkZXIocm93bmFtZXModGFiQ1AxKSwtcmFuayhOT01fcHZhbCkpLCB5PS1sb2cxMChOT01fcHZhbCksZmlsbD0tbG9nMTAoTk9NX3B2YWwpKSkgK2dlb21fY29sKHdpZHRoPS42NSkrIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93PSIjRjZCREMwIixoaWdoPSIjREMxQzEzIikrdGhlbWUoYXhpcy50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTgpKSArIHNjYWxlX3hfZGlzY3JldGUobGFiZWwgPSBmdW5jdGlvbih4KSBzdHJpbmdyOjpzdHJfd3JhcChnc3ViKCJfIiwgIiAiLHgpLCB3aWR0aCA9IDMwKSkgKyB4bGFiKCIiKSsgbGFicyggdGl0bGUgPSAiQ1dNIHZzIFdNTCIsIHN1YnRpdGxlID0gIkdPIFRyYW5zY3JpcHRpb24gZmFjdG9yIHRhcmdldHMgMjAyMSIpICsgY29vcmRfZmxpcCgpK3RoZW1lX2J3KCkKYGBgCgojIyBLRUdHIHBhdGh3YXkgZGF0YWJhc2Ugey50YWJzZXR9CmBgYHtyIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcGFnZWQucHJpbnQ9RkFMU0UsIGZpZy53aWR0aCA9IDgsIGZpZy5oZWlnaHQgPSA3fQojI3BhdGh3YXkKc3BlY2lmaWNBUCA9IGFzLmNoYXJhY3RlcihuYS5vbWl0KGRlZ3MuQVBbIWRlZ3MuQVAlaW4lZGVncy5CUCAmICFkZWdzLkFQJWluJWRlZ3MuQ1BdKSkKc3BlY2lmaWNCUCA9IGFzLmNoYXJhY3RlcihuYS5vbWl0KGRlZ3MuQlBbIWRlZ3MuQlAlaW4lZGVncy5BUCAmICFkZWdzLkJQJWluJWRlZ3MuQ1BdKSkKc3BlY2lmaWNDUCA9IGFzLmNoYXJhY3RlcihuYS5vbWl0KGRlZ3MuQ1BbIWRlZ3MuQ1AlaW4lZGVncy5BUCAmICFkZWdzLkNQJWluJWRlZ3MuQlBdKSkKCmxpc3RQID0gbGlzdChzcGVjaWZpY0FQPXNwZWNpZmljQVAsIHNwZWNpZmljQlA9c3BlY2lmaWNCUCxzcGVjaWZpY0NQPXNwZWNpZmljQ1ApCmZpc2hQID0gZmlzaGVyX2VucmljaG1lbnQobGlzdFAsa2VnZyx1bmlxdWUocmVzLlQkc3ltYm9sKSkKCiMjdG9wMTAgcGF0aHdheSBLRUdHCnRhYkFQIDwtIGZpc2hQJHNwZWNpZmljQVAKdGFiQVAkZmRyIDwtIGFzLm51bWVyaWModGFiQVAkZmRyKSAKdGFiQVAkT1Iub2Rkcy5yYXRpbyA8LSBhcy5udW1lcmljKHRhYkFQJE9SLm9kZHMucmF0aW8pIAp0YWJBUCROT01fcHZhbCA8LSBhcy5udW1lcmljKHRhYkFQJE5PTV9wdmFsKQp0YWJBUD10YWJBUFtvcmRlcih0YWJBUCROT01fcHZhbCksXQp0b3BBUCA9IHN1YnNldCh0YWJBUCxOT01fcHZhbDw9MC4xNykKdG9wQVAkcGF0aHdheSA9IHJvd25hbWVzKHRvcEFQKQp0YWJBUDEgPC0gdGFiQVBbbWF0Y2gocm93bmFtZXModG9wQVApLCByb3duYW1lcyh0YWJBUCkpLF0Kcm93bmFtZXModGFiQVAxKSA8LSBnc3ViKCJLRUdHIiwgIiIscm93bmFtZXModGFiQVAxKSkgCnJvd25hbWVzKHRhYkFQMSkgPC0gZ3N1YigiXyIsICIgIixyb3duYW1lcyh0YWJBUDEpKSAKcm93bmFtZXModGFiQVApIDwtIGdzdWIoIktFR0ciLCAiIixyb3duYW1lcyh0YWJBUCkpIApyb3duYW1lcyh0YWJBUCkgPC0gZ3N1YigiXyIsICIgIixyb3duYW1lcyh0YWJBUCkpIAoKdGFiQlAgPC0gZmlzaFAkc3BlY2lmaWNCUAp0YWJCUCRmZHIgPC0gYXMubnVtZXJpYyh0YWJCUCRmZHIpCnRhYkJQJE9SLm9kZHMucmF0aW8gPC0gYXMubnVtZXJpYyh0YWJCUCRPUi5vZGRzLnJhdGlvKSAKdGFiQlAkTk9NX3B2YWwgPC0gYXMubnVtZXJpYyh0YWJCUCROT01fcHZhbCkKdGFiQlA9dGFiQlBbb3JkZXIodGFiQlAkTk9NX3B2YWwpLF0KdG9wQlAgPSBzdWJzZXQodGFiQlAsTk9NX3B2YWw8PTAuMykKdG9wQlAkcGF0aHdheSA9IHJvd25hbWVzKHRvcEJQKQp0YWJCUDEgPC0gdGFiQlBbbWF0Y2gocm93bmFtZXModG9wQlApLCByb3duYW1lcyh0YWJCUCkpLF0KdGFiQlAxIDwtIHRhYkJQMVsxOjEwLF0Kcm93bmFtZXModGFiQlAxKSA8LSBnc3ViKCJLRUdHIiwgIiIscm93bmFtZXModGFiQlAxKSkgCnJvd25hbWVzKHRhYkJQMSkgPC0gZ3N1YigiXyIsICIgIixyb3duYW1lcyh0YWJCUDEpKSAKcm93bmFtZXModGFiQlApIDwtIGdzdWIoIktFR0ciLCAiIixyb3duYW1lcyh0YWJCUCkpIApyb3duYW1lcyh0YWJCUCkgPC0gZ3N1YigiXyIsICIgIixyb3duYW1lcyh0YWJCUCkpIAoKdGFiQ1AgPC0gZmlzaFAkc3BlY2lmaWNDUAp0YWJDUCRmZHIgPC0gYXMubnVtZXJpYyh0YWJDUCRmZHIpCnRhYkNQJE9SLm9kZHMucmF0aW8gPC0gYXMubnVtZXJpYyh0YWJDUCRPUi5vZGRzLnJhdGlvKSAKdGFiQ1AkTk9NX3B2YWwgPC0gYXMubnVtZXJpYyh0YWJDUCROT01fcHZhbCkKdG9wQ1AgPC0gdG9wUGF0aChmaXNoUCAsInNwZWNpZmljQ1AiLCAwLjUsIDEyKQp0YWJDUDEgPC0gdGFiQ1BbbWF0Y2godG9wQ1AsIHJvd25hbWVzKHRhYkNQKSksXQpyb3duYW1lcyh0YWJDUDEpIDwtIGdzdWIoIktFR0ciLCAiIixyb3duYW1lcyh0YWJDUDEpKSAKcm93bmFtZXModGFiQ1AxKSA8LSBnc3ViKCJfIiwgIiAiLHJvd25hbWVzKHRhYkNQMSkpIApyb3duYW1lcyh0YWJDUCkgPC0gZ3N1YigiS0VHRyIsICIiLHJvd25hbWVzKHRhYkNQKSkgCnJvd25hbWVzKHRhYkNQKSA8LSBnc3ViKCJfIiwgIiAiLHJvd25hbWVzKHRhYkNQKSkgCmBgYAoKCiMjIyBUb3AgMTAgcGF0aHdheSBDV00gdnMgTkFXTQpgYGB7ciBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIHBhZ2VkLnByaW50PUZBTFNFLCBmaWcud2lkdGggPSA0LCBmaWcuaGVpZ2h0ID0gM30KZ2dwbG90KHRhYkFQMSwgYWVzKHg9cmVvcmRlcihyb3duYW1lcyh0YWJBUDEpLC1yYW5rKE5PTV9wdmFsKSksIHk9LWxvZzEwKE5PTV9wdmFsKSxmaWxsPS1sb2cxMChOT01fcHZhbCkpKSArZ2VvbV9jb2wod2lkdGg9LjY1KSsgc2NhbGVfZmlsbF9ncmFkaWVudChsb3c9IiNGNkJEQzAiLGhpZ2g9IiNEQzFDMTMiKSArdGhlbWUoYXhpcy50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTgpKSArIHNjYWxlX3hfZGlzY3JldGUobGFiZWwgPSBmdW5jdGlvbih4KSBzdHJpbmdyOjpzdHJfd3JhcChnc3ViKCJfIiwgIiAiLHgpLCB3aWR0aCA9IDMwKSkgKyBsYWJzKHRpdGxlID0gIkNXTSB2cyBOQVdNIiwgc3VidGl0bGUgPSAiR08gS0VHRyBwYXRod2F5IGRhdGFiYXNlIDIwMjEiKSArIHhsYWIoIiIpICsgY29vcmRfZmxpcCgpICsgdGhlbWVfYncoKQpgYGAKCgojIyMgVG9wIDEwIHBhdGh3YXkgTkFXTSB2cyBXTUwKYGBge3IgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBwYWdlZC5wcmludD1GQUxTRSwgZmlnLndpZHRoID0gNCwgZmlnLmhlaWdodCA9IDN9CmdncGxvdCh0YWJCUDEsIGFlcyh4PXJlb3JkZXIocm93bmFtZXModGFiQlAxKSwtcmFuayhOT01fcHZhbCkpLCB5PS1sb2cxMChOT01fcHZhbCksZmlsbD0tbG9nMTAoTk9NX3B2YWwpKSkgK2dlb21fY29sKHdpZHRoPS42NSkrIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93PSIjRjZCREMwIixoaWdoPSIjREMxQzEzIikrdGhlbWUoYXhpcy50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTgpKSArIHNjYWxlX3hfZGlzY3JldGUobGFiZWwgPSBmdW5jdGlvbih4KSBzdHJpbmdyOjpzdHJfd3JhcChnc3ViKCJfIiwgIiAiLHgpLCB3aWR0aCA9IDMwKSkgKyB4bGFiKCIiKSsgbGFicyh0aXRsZSA9ICJOQVdNIHZzIFdNTCIsIHN1YnRpdGxlID0gIkdPIEtFR0cgcGF0aHdheSBkYXRhYmFzZSAyMDIxIikgKyBjb29yZF9mbGlwKCkrIHRoZW1lX2J3KCkKYGBgCgoKIyMjIFRvcCAxMCBwYXRod2F5IENXTSB2cyBXTUwKYGBge3IgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBwYWdlZC5wcmludD1GQUxTRSwgZmlnLndpZHRoID0gNCwgZmlnLmhlaWdodCA9IDN9CmdncGxvdCh0YWJDUDEsIGFlcyh4PXJlb3JkZXIocm93bmFtZXModGFiQ1AxKSwtcmFuayhOT01fcHZhbCkpLCB5PS1sb2cxMChOT01fcHZhbCksZmlsbD0tbG9nMTAoTk9NX3B2YWwpKSkgK2dlb21fY29sKHdpZHRoPS42NSkrIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93PSIjRjZCREMwIixoaWdoPSIjREMxQzEzIikrdGhlbWUoYXhpcy50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTgpKSArIHNjYWxlX3hfZGlzY3JldGUobGFiZWwgPSBmdW5jdGlvbih4KSBzdHJpbmdyOjpzdHJfd3JhcChnc3ViKCJfIiwgIiAiLHgpLCB3aWR0aCA9IDMwKSkgKyB4bGFiKCIiKSsgbGFicyggdGl0bGUgPSAiQ1dNIHZzIFdNTCIsIHN1YnRpdGxlID0gIkdPIEtFR0cgcGF0aHdheSBkYXRhYmFzZSAyMDIxIikgKyBjb29yZF9mbGlwKCkrdGhlbWVfYncoKQpgYGAKCgoKCgo=